2013-02-25 9 views
5

Wiem, że nie można używać przechodzenia stylu wątku w łańcuchach dla współrzędnych kodowych większych niż^(FF) w Rebol 2, ponieważ nie wie nic o Unicode. Więc to nie generuje coś dobrze, to wygląda pomieszane:Jak używać punktów kodowych Unicode powyżej U + FFFF w ciągach Rebol 3 jak w Rebol 2?

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

Jeszcze kod działa w REBOL 3 i wypisuje:

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

to świetnie, ale R3 maxes się jego zdolność do utrzymywania znak w ciągu znaków w ogóle u + FFFF widocznie:

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

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

sytuacja jest o wiele lepsza niż losowe zachowanie REBOL 2, gdy spełnione codepoints nie wiedzieć. Jednak w Rebolie istniało obejście do przechowywania ciągów znaków, jeśli wiedziałeś, jak tworzyć własne kodowanie UTF-8 (lub otrzymałeś ciągi znaków przez ładowanie kodu źródłowego z dysku). Można je po prostu połączyć z indywidualnymi postaciami.

Tak kodowanie UTF-8 U + 010000 # F0908080 jest, i można powiedzieć przed:

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

I chcesz uzyskać ciąg z tego jednego kodowy zakodowanego przy użyciu UTF-8, to ty można zapisać na dysku w blokach kodu i ponownie wczytać. Czy jest jakaś podobna sztuczka w R3?

Odpowiedz

3

Tak, jest pewna sztuczka ... która jest sztuczką, którą powinieneś używać również w R2. Nie używaj sznurka! Użyj pliku binarnego! jeśli trzeba robić tego typu rzeczy:

dobrej Obejście: # {F0908080}

Byłoby Pracowałam w Rebol2 i działa w Rebol3. Możesz go zapisać i załadować bez żadnych zabawnych transakcji.

W rzeczywistości, jeśli troska o Unicode w ogóle, kiedykolwiek ... przestać robić przetwarzania ciąg, który używa codepoints wyższe niż^(7F), jeśli tkwią w REBOL 2, a nie 3. Zobaczymy, dlaczego patrząc na tego strasznego rozwiązania:

straszny-obejście: dołączyć [# "^ (F0)" # "^ (90)" # "^ (80)" # "^ (80) "]

... «I chcesz uzyskać ciąg z tego jednego UTF-8 punkt kodowy» ...

tylko rzeczą, jaką należy uzyskać to ciąg z czterech kodepody poszczególnych znaków, oraz z 4 = length? terrible-workaround. Rebol2 jest zepsuty, ponieważ string! zasadniczo nie różni się od binarnego! pod maską. W rzeczywistości, w Rebol2 można pseudonimie tych dwóch typów bez wykonywania kopii, spójrz na AS-BINARY i AS-STRING. (Jest to niemożliwe w Rebol3, ponieważ są one zasadniczo fundamentalnie różne, więc nie przywiązuj się do tej funkcji!)

To trochę złudne, że te ciągi mają długość 4, a każdy znak powoduje fałszywy komfort ta sama wartość, jeśli konwertujesz je to integer!. Ponieważ jeśli kiedykolwiek napiszesz je do jakiegoś pliku lub portu i trzeba je zakodować, zostaniesz ugryziony.Warto zauważyć, że w Rebol2:

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

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

Ale w R3, masz kodowanie UTF-8, gdy potrzebna jest konwersja binarny:

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

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

Więc będzie niespodzianka po kodzie pozornie pracujących robi coś innego w późniejszym czasie, a inaczej serializuje. W rzeczywistości, jeśli chcesz wiedzieć, w jaki sposób "pomieszany" R2 jest pod tym względem, spójrz, dlaczego masz dziwny symbol swojego "mu". W R2:

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

Po prostu wyrzucił "03". : -/

Więc jeśli z jakiegoś powodu trzeba pracować z ciągów znaków Unicode i nie można przełączyć do R3, spróbuj coś takiego na przykład krowy:

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

Że dostaje binarnego. Przekonwertuj go tylko na ciąg znaków do debugowania i przygotuj się na bełkot. Ale jest to słuszne, jeśli utkniesz w Rebol2.

I powtórzyć odpowiedź: to także, co zrobić, jeśli z jakiegoś dziwnego powodu zatrzymany, która chciałaby korzystać z tych wyższych codepoints w Rebol3:

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

Jestem pewien, że byłoby to bardzo zabawny żart, gdybym wiedział, co to jest LINEAR B SYLLABLE B008 A. Co prowadzi mnie do stwierdzenia, że ​​najprawdopodobniej, jeśli robisz coś takiego, , ten ezoteryczny prawdopodobnie ma tylko kilka punktów kodowych, które są cytowane jako przykłady. Możesz przechowywać większość danych w postaci ciągu znaków, aż do momentu, w którym będziesz musiał je wygodnie umieścić w gnieździe i trzymać wynik w serii binarnej.


UPDATE: Jeśli ktoś uderza ten problem, tu jest funkcją narzędzie, które może być przydatne do pracy wokół niego tymczasowo:

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 
] 

Jeśli używasz tego zamiast to binary! nawrócenia, ty uzyska spójne zachowanie zarówno w Rebol2, jak i Rebol3. (Skutecznie implementuje rozwiązanie dla ciągów stylów terrible-workaround).

3

Istnieje obejście z użyciem ciągu znaków! również typ danych. Nie można używać UTF-8 w tym przypadku, ale można użyć UTF-16 obejście następująco:

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

, który koduje^(10000) litera kodu przy użyciu UTF-16 zastępczą parę. Zasadniczo do kodowania można użyć następującej funkcji:

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"] 
    ] 
] 
Powiązane problemy