2013-02-25 23 views
5

我知道你不能在Rebol 2中使用大于^(FF)的代码点在字符串中转义的脱字符号样式,因为它不知道任何有关Unicode的内容。因此,这不会产生什么好东西,它看起来很乱:如何在Rebol 3字符串中使用U + FFFF以上的Unicode代码点,如在Rebol 2中?

print {Q: What does a Zen master's {Cow} Say? A: "^(03BC)"!} 

然而,代码在雷博尔3,并打印出:

Q: What does a Zen master's {Cow} Say? A: "μ"! 

这是伟大的,但R3马克塞斯其持有的能力在字符串中的字符都在U + FFFF明显:

>> type? "^(FFFF)" 
== string! 

>> type? "^(010000)" 
** Syntax error: invalid "string" -- {"^^(010000)"} 
** Near: (line 1) type? "^(010000)" 

的情况比雷博尔2的随机行为,当它遇到的代码点它不知道好了很多。但是,如果您知道如何执行您自己的UTF-8编码(或通过将源代码加载到磁盘上的方式获得您的字符串),那么在Rebol中用于存储字符串的方法曾经是一种解决方法。你可以将它们从单个字符组合起来。

所以U + 010000的UTF-8编码为#F0908080,你可以说前:

workaround: rejoin [#"^(F0)" #"^(90)" #"^(80)" #"^(80)"] 

而且你会得到使用编码的单码点串UTF-8,你可以用代码块保存到磁盘并再次读回。 R3有没有类似的技巧?

回答

3

是的,有一个技巧......这也是你应该在R2中使用的技巧。 请勿使用字符串!使用二进制文件!如果你必须做这样的事情:

好解决方法:#{} F0908080

这将在Rebol2工作过,并且它Rebol3工作。您可以保存并加载它,而无需任何有趣的业务。

事实上,如果关心Unicode的话,永远...... 停止使用比^(7F)更高的代码点的字符串处理,如果您被困在Rebol 2中而不是3。我们将看到为什么通过寻找那种可怕的解决方法:

糟糕的解决方法:rejoin [#“^(F0)”#“^(90)”#“^(80)”#“^(80 )“]

... ‘你会得到与单UTF-8码点’串...

只有件事你应该得到的是四个串个别字符码点,并与4 = length? terrible-workaround。 Rebol2被破坏,因为字符串!与二进制文件基本没有区别!在引擎盖下。实际上,在Rebol2中,您可以将这两种类型来回混叠,而不需要复制,查找AS-BINARY和AS-STRING。 (这在Rebol3中是不可能的,因为它们真的有根本的不同,所以不要附在这个功能上!)

看到这些字符串报告长度为4,并且每个字符产生一个虚假的舒适度如果将它们转换成相同的值to integer!。因为如果你将它们写出到某个文件或端口,并且需要编码,你会被咬。注意,这在Rebol2:

>> to integer! #"^(80)" 
== 128 

>> to binary! #"^(80)" 
== #{80} 

但R3,你有一个UTF-8编码时,需要二进制转换:

>> to integer! #"^(80)" 
== 128 

>> to binary! #"^(80)" 
== #{C280} 

所以你会在一个惊喜,当你看似工作的代码在稍后的时间做了一些不同的事情,并以不同的方式进行序列化。事实上,如果你想知道R2在这方面是如何“搞砸”的,那么看看为什么你的“mu”有一个奇怪的符号。在R2中:

>> to binary! #"^(03BC)" 
== #{BC} 

它只是扔掉了“03”。 : -/

所以如果你需要某种原因与Unicode字符串工作,不能切换到R3,尝试这样的事情对于牛例如:

mu-utf8: #{03BC} 
utf8: rejoin [#{} {Q: What does a Zen master's {Cow} Say? A: "} mu-utf8 {"!}] 

,让你一个二进制文件。只能将其转换为字符串以进行调试输出,并准备好看到乱码。但如果你被困在Rebol2中,这是正确的。

,并重申了答案:这也是如果坚持一些奇怪的原因需要在Rebol3使用这些更高的码点做什么:

utf8: rejoin [#{} {Q: What did the Mycenaean's {Cow} Say? A: "} #{010000} {"!}] 

我敢肯定,如果我这将是一个非常有趣的笑话知道什么LINEAR B SYLLABLE B008 A是。这使我最有可能说,如果你正在做一些这个深奥的,你可能只会列举一些代码点作为例子。您可以将大部分数据保存为字符串,直到您需要方便地插入它们,并将结果保存为二进制序列。


UPDATE:如果一个人打这个问题,这里是一个实用功能,可以暂时围绕它的工作是有用的:如果你使用这个,而不是一个to binary!转换

safe-r2-char: charset [#"^(00)" - #"^(7F)"] 
unsafe-r2-char: charset [#"^(80)" - #"^(FF)"] 
hex-digit: charset [#"0" - #"9" #"A" - #"F" #"a" - #"f"] 

r2-string-to-binary: func [ 
    str [string!] /string /unescape /unsafe 
    /local result s e escape-rule unsafe-rule safe-rule rule 
] [ 
    result: copy either string [{}] [#{}] 
    escape-rule: [ 
     "^^(" s: 2 hex-digit e: ")" (
      append result debase/base copy/part s e 16 
     ) 
    ] 
    unsafe-rule: [ 
     s: unsafe-r2-char (
      append result to integer! first s 
     ) 
    ] 
    safe-rule: [ 
     s: safe-r2-char (append result first s) 
    ] 
    rule: compose/deep [ 
     any [ 
      (either unescape [[escape-rule |]] []) 
      safe-rule 
      (either unsafe [[| unsafe-rule]] []) 
     ] 
    ] 
    unless parse/all str rule [ 
     print "Unsafe codepoints found in string! by r2-string-to-binary" 
     print "See http://stackoverflow.com/questions/15077974/" 
     print mold str 
     throw "Bad codepoint found by r2-string-to-binary" 
    ] 
    result 
] 

,你将在Rebol2和Rebol3中获得一致的行为。 (它有效地实现了terrible-workaround风格字符串的解决方案。)

3

有一种使用字符串的解决方法!数据类型。不能在这种情况下使用UTF-8,但可以使用UTF-16的解决方法如下:

utf-16: "^(d800)^(dc00)" 

,其编码^(10000)代码中使用UTF-16代理对点。通常,以下功能可以进行编码:

utf-16: func [ 
    code [integer!] 
    /local low high 
] [ 
    case [ 
     code < 0 [do make error! "invalid code"] 
     code < 65536 [append copy "" to char! code] 
     code < 1114112 [ 
      code: code - 65536 
      low: code and 1023 
      high: code - low/1024 
      append append copy "" to char! high + 55296 to char! low + 56320 
     ] 
     'else [do make error! "invalid code"] 
    ] 
] 
相关问题