我知道你不能在Rebol 2中使用大于^(FF)的代码点在字符串中使用插入符号样式,因为它对Unicode没有任何了解。所以这并没有产生任何好处,它看起来搞砸了:
print {Q: What does a Zen master's {Cow} Say? A: "^(03BC)"!}
然而,代码在Rebol 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)"
当Rebol 2遇到它不知道的代码点时,情况要好于Rebol 2的随机行为。但是,如果您知道如何进行自己的UTF-8编码(或通过从磁盘加载源代码获取字符串),Rebol中常常会有一种解决方法来存储字符串。你可以从单个角色组装它们。
所以U + 010000的UTF-8编码是#F0908080,你可以说:
workaround: rejoin [#"^(F0)" #"^(90)" #"^(80)" #"^(80)"]
你会得到一个字符串,其中包含使用UTF-8编码的单个代码点,您可以在代码块中保存到磁盘并再次读回。 R3中有类似的技巧吗?
答案 0 :(得分:4)
使用字符串有一种解决方法!数据类型也是如此。在这种情况下,您不能使用UTF-8,但您可以按如下方式使用UTF-16解决方法:
utf-16: "^(d800)^(dc00)"
,使用UTF-16代理项对^(10000)代码点进行编码。通常,以下函数可以执行编码:
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"]
]
]
答案 1 :(得分:3)
是的,有一个技巧......这也是你应该在R2中使用的技巧。 不要使用字符串!使用二进制!如果你必须这样做:
好的解决方法:#{F0908080}
它可以在Rebol2中运行,它可以在Rebol3中运行。你可以保存它并加载它而没有任何有趣的业务。
事实上,如果完全关心Unicode,那么...... 停止使用高于^(7F)的代码点的字符串处理,如果你被困在Rebol 2而不是3 。我们会通过观察那个可怕的解决方法来了解原因:
糟糕的解决方法:重新加入[#“^(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是什么,我肯定这将是一个非常有趣的笑话。这让我更有可能说,如果你正在做一些这个深奥的,你可能只会引用一些代码点作为例子。您可以将大部分数据保存为字符串,直到您需要方便地插入它们,并将结果保存为二进制序列。
更新:如果遇到此问题,这里有一个实用程序功能,可以暂时解决它:
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
]
如果您使用此转换而不是to binary!
转换,您将在Rebol2和Rebol3中获得一致的行为。 (它有效地实现了terrible-workaround
样式字符串的解决方案。)