2013-02-25 24 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"] 
    ] 
] 
相關問題