是的,有一个技巧……这也是您应该在 R2 中使用的技巧。 不要使用字符串!使用二进制!如果你必须做这种事情:
好的解决方法:#{F0908080}
它可以在 Rebol2 中工作,在 Rebol3 中也可以工作。您可以保存并加载它而无需任何有趣的事情。
事实上,如果你完全关心 Unicode,永远......如果你被困在 Rebol 2 而不是 3 中,请停止使用高于 ^(7F) 的代码点进行字符串处理。我们将通过查看那个可怕的解决方法来了解原因:
糟糕的解决方法:重新加入 [#"^(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
样式字符串的解决方案。)