Zastanawiam się, dlaczego większość nowoczesnych rozwiązań zbudowanych przy użyciu Perla domyślnie nie włącza UTF-8 .
Rozumiem, że istnieje wiele starszych problemów dla podstawowych skryptów Perla, w których może to popsuć. Jednak z mojego punktu widzenia w XXI wieku duże nowe projekty (lub projekty z dużą perspektywą) powinny sprawić, by ich oprogramowanie UTF-8 było od podstaw odporne. Nadal nie widzę, żeby to się działo. Na przykład Łoś włącza surowe i ostrzeżenia, ale nie Unicode . Modern :: Perl redukuje również płytę kotłową, ale nie obsługuje UTF-8.
Dlaczego? Czy istnieją jakieś powody, aby unikać UTF-8 w nowoczesnych projektach Perla w 2011 roku?
Komentowanie @tchrist stało się zbyt długie, więc dodaję to tutaj.
Wygląda na to, że nie wyraziłem się jasno. Pozwól mi spróbować dodać kilka rzeczy.
tchrist i ja widzimy sytuację dość podobnie, ale nasze wnioski są całkowicie przeciwne. Zgadzam się, sytuacja w Unicode jest skomplikowana, ale dlatego my (użytkownicy Perla i kodery) potrzebujemy warstwy (lub pragmy), która sprawia, że obsługa UTF-8 jest tak łatwa, jak musi być teraz.
tchrist wskazał na wiele aspektów do omówienia, będę czytać i myśleć o nich przez kilka dni, a nawet tygodni. Jednak nie o to mi chodzi. tchrist próbuje udowodnić, że nie ma jednego sposobu „włączenia UTF-8”. Nie mam zbyt dużej wiedzy, aby się z tym kłócić. Trzymam się więc przykładów na żywo.
Grałem z Rakudo, a UTF-8 był tam, gdzie potrzebowałem . Nie miałem żadnych problemów, po prostu działało. Może są jakieś ograniczenia gdzieś głębiej, ale na początku wszystko, co testowałem, działało zgodnie z oczekiwaniami.
Czy nie powinien to być również cel w nowoczesnym Perlu 5? Podkreślam to bardziej: nie sugeruję UTF-8 jako domyślnego zestawu znaków dla podstawowego Perla, sugeruję możliwość uruchomienia go za pomocą przystawki dla tych, którzy opracowują nowe projekty.
Kolejny przykład, ale z bardziej negatywnym tonem. Ramy powinny ułatwić rozwój. Kilka lat temu próbowałem frameworków internetowych, ale po prostu je wyrzuciłem, ponieważ „włączenie UTF-8” było tak niejasne. Nie znalazłem jak i gdzie podpiąć obsługę Unicode. To było tak czasochłonne, że łatwiej mi było pójść starą drogą. Teraz widziałem tutaj, że istnieje nagroda za rozwiązanie tego samego problemu z Masonem 2: Jak sprawić, by Mason2 UTF-8 był czysty? . Jest to więc całkiem nowy framework, ale używanie go z UTF-8 wymaga głębokiej znajomości jego wewnętrznych elementów. To jest jak duży czerwony znak: STOP, nie używaj mnie!
Naprawdę lubię Perla. Ale radzenie sobie z Unicode jest bolesne. Nadal czuję, że biegnę po ścianach. W pewien sposób tchrist ma rację i odpowiada na moje pytania: nowe projekty nie przyciągają UTF-8, ponieważ jest to zbyt skomplikowane w Perlu 5.
Odpowiedzi:
𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 ℞ : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨
Ustaw swoją
PERL_UNICODE
zmienną naAS
. To powoduje, że wszystkie skrypty Perla dekodują@ARGV
jako ciągi UTF ‑ 8, i ustawia kodowanie wszystkich trzech stdin, stdout i stderr na UTF ‑ 8. Oba są efektami globalnymi, a nie leksykalnymi.W górnej części pliku źródłowego (program, moduł, biblioteka,
do
hickey) wyraźnie zaznacz, że korzystasz z Perla w wersji 5.12 lub nowszej poprzez:Włącz ostrzeżenia, ponieważ poprzednia deklaracja włącza tylko ograniczenia i funkcje, a nie ostrzeżenia. Sugeruję również promowanie ostrzeżeń Unicode w wyjątki, więc używaj obu tych linii, a nie tylko jednej. Uwaga jednak, że pod v5.14 The
utf8
klasa ostrzeżenie obejmuje trzy inne subwarnings które mogą być osobno włączone:nonchar
,surrogate
, inon_unicode
. Te możesz chcieć mieć większą kontrolę.Oświadcz, że ta jednostka źródłowa jest zakodowana jako UTF ‑ 8. Chociaż kiedyś ta pragma robiła inne rzeczy, teraz służy tylko temu jednemu celowi i żadnemu innemu:
Zadeklaruj, że wszystko, co otwiera uchwyt pliku w tym zakresie leksykalnym, ale nie gdzie indziej, zakłada, że ten strumień jest zakodowany w UTF-8, chyba że powiesz inaczej. W ten sposób nie wpływasz na kod innego modułu lub innego programu.
Włącz nazwane znaki przez
\N{CHARNAME}
.Jeśli masz
DATA
uchwyt, musisz jawnie ustawić jego kodowanie. Jeśli chcesz, aby to był UTF ‑ 8, powiedz:Oczywiście nie ma końca innymi sprawami, którymi możesz się w końcu zająć, ale wystarczą one do przybliżenia celu państwa, jakim jest „sprawienie, by wszystko działało tylko z UTF ‑ 8”, choć dla nieco osłabionego rozumienia tych terminów.
Jeszcze jedna pragma, choć nie jest związana z Unicode, to:
Jest to zdecydowanie zalecane.
🌴 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐁
🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 🎁
Moja własna płyta dziś wygląda tak:
🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅
Mówiąc, że „Perl powinien [ jakoś! ] włącz Unicode domyślnie ”nawet nie zaczyna myśleć o tym, aby powiedzieć wystarczająco dużo, aby być nawet marginalnie przydatnym w jakimś rzadkim i odosobnionym przypadku. Unicode to znacznie więcej niż tylko większy repertuar postaci; to także sposób, w jaki wszystkie te postacie oddziałują na wiele, wiele sposobów.
Nawet proste, minimalne miary, które (niektórzy) ludzie myślą, że chcą, nieszczęśliwie łamią miliony linii kodu, kodu, który nie ma szansy na „uaktualnienie” do nowej, wspaniałej nowoczesności Brave New World .
Jest to o wiele bardziej skomplikowane niż ludzie udają. Przez ostatnie kilka lat myślałem o tym bardzo dużo. Chciałbym pokazać, że się mylę. Ale nie wydaje mi się. Unicode jest zasadniczo bardziej złożony niż model, który chciałbyś na niego nałożyć, a tutaj jest złożoność, której nigdy nie można zamiatać pod dywan. Jeśli spróbujesz, złamiesz swój własny kod lub kod innej osoby. W pewnym momencie musisz po prostu się zepsuć i dowiedzieć się, o co chodzi w Unicode. Nie możesz udawać, że to coś, czym nie jest.
🐪 robi wszystko, aby Unicode był łatwy, znacznie bardziej niż cokolwiek innego, z czego kiedykolwiek korzystałem. Jeśli uważasz, że to źle, spróbuj na chwilę zrobić coś innego. Następnie wróć do 🐪: albo wrócisz do lepszego świata, albo przyniesiesz ze sobą wiedzę o tym samym, abyśmy mogli wykorzystać twoją nową wiedzę, aby ulepszyć these w tych sprawach.
💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙 💡
Oto co najmniej kilka rzeczy, które wydają się być wymagane, aby 🐪 „domyślnie włączał Unicode”, jak to ująłeś:
Kod źródłowy 🐪 powinien być domyślnie w UTF-8. Możesz to uzyskać za pomocą
use utf8
lubexport PERL5OPTS=-Mutf8
.DATA
Uchwyt 🐪 powinien być UTF-8. Będziesz musiał to zrobić dla poszczególnych pakietów, jak wbinmode(DATA, ":encoding(UTF-8)")
.Domyślnie argumenty programu do skryptów 🐪 powinny być rozumiane jako UTF-8.
export PERL_UNICODE=A
lubperl -CA
lubexport PERL5OPTS=-CA
.Standardowe strumienie danych wejściowych, wyjściowych i błędów powinny być domyślnie ustawione na UTF-8.
export PERL_UNICODE=S
dla wszystkich z nich, alboI
,O
i / lubE
do tylko niektórych z nich. To jest jakperl -CS
.Wszelkie inne uchwyty otwarte przez 🐪 powinny być traktowane jako UTF-8, chyba że podano inaczej;
export PERL_UNICODE=D
lub zi
io
dla określonych z nich;export PERL5OPTS=-CD
pracowałbym. To sprawia, że-CSAD
dla nich wszystkich.Pokryj obie bazy i wszystkie otwarte strumienie
export PERL5OPTS=-Mopen=:utf8,:std
. Zobacz unikat .Nie chcesz przegapić błędów kodowania UTF-8. Spróbować
export PERL5OPTS=-Mwarnings=FATAL,utf8
. I upewnij się, że twoje strumienie wejściowe są zawszebinmode
do:encoding(UTF-8)
, a nie tylko do:utf8
.Punkty kodowe między 128–255 należy rozumieć przez 🐪 jako odpowiadające punkty kodowe Unicode, a nie tylko niepoprawne wartości binarne.
use feature "unicode_strings"
lubexport PERL5OPTS=-Mfeature=unicode_strings
. To sprawi, żeuc("\xDF") eq "SS"
i"\xE9" =~ /\w/
. Prostyexport PERL5OPTS=-Mv5.12
lub lepszy również to dostanie.Nazwane znaki Unicode nie są domyślnie włączone, więc dodaj
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
lub niektóre z nich. Zobacz uninames i tcgrep .Prawie zawsze potrzebujesz dostępu do funkcji ze standardowego
Unicode::Normalize
modułu różnego rodzaju rozkładów.export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
, a następnie zawsze uruchamiaj przychodzące rzeczy przez NFD i wychodzące rzeczy z NFC. Nie ma jeszcze dla nich żadnej warstwy I / O, ale zobacz nfc , nfd , nfkd i nfkc .Porównywanie łańcuchów w 🐪 użyciu
eq
,ne
,lc
,cmp
,sort
, & c & cc zawsze są błędne. Więc zamiast tego@a = sort @b
potrzebujesz@a = Unicode::Collate->new->sort(@b)
. Równie dobrze dodaj to do swojegoexport PERL5OPTS=-MUnicode::Collate
. Możesz buforować klucz do porównań binarnych.🐪 wbudowane lubią
printf
iwrite
robią coś złego z danymi Unicode. Trzeba korzystać zUnicode::GCString
modułu dla tych pierwszych, i że zarówno a także moduł , jak również dla tych drugich. Zobacz uwc i unifmt .Unicode::LineBreak
Jeśli chcesz, aby liczyły się jako liczby całkowite, będziesz musiał uruchomić
\d+
przechwytywanie przez tęUnicode::UCD::num
funkcję, ponieważ wbudowane atoi (3) 3 nie jest obecnie wystarczająco sprytne.Będziesz mieć problemy z systemem plików na 👽 systemach plików. Niektóre systemy plików po cichu wymuszają konwersję do NFC; inni po cichu wymuszają konwersję na NFD. A inni robią coś jeszcze. Niektórzy nawet całkowicie ignorują tę sprawę, co prowadzi do jeszcze większych problemów. Musisz więc zachować własną obsługę NFC / NFD, aby zachować rozsądek.
Wszystkie Twoje 🐪 kod z udziałem
a-z
lubA-Z
i takie muszą zostać zmienione , w tymm//
,s///
itr///
. Powinien się wyróżniać jako krzycząca czerwona flaga, że Twój kod jest uszkodzony. Ale nie jest jasne, jak musi się to zmienić. Uzyskanie właściwych właściwości i zrozumienie ich folderów jest trudniejsze niż mogłoby się wydawać. Używam unichars i uniprops każdego dnia.Kod, który używa,
\p{Lu}
jest prawie tak samo zły, jak kod, który używa[A-Za-z]
. Musisz użyć\p{Upper}
zamiast tego i znać powód. Tak\p{Lowercase}
i\p{Lower}
różnią się od\p{Ll}
i\p{Lowercase_Letter}
.Kod, który używa,
[a-zA-Z]
jest jeszcze gorszy. I nie może użyć\pL
lub\p{Letter}
; musi użyć\p{Alphabetic}
. Wiesz, nie wszystkie alfabetyty to litery.Jeśli szukasz 🐪 zmiennych
/[\$\@\%]\w+/
, masz problem. Musisz szukać/[\$\@\%]\p{IDS}\p{IDC}*/
, a nawet to nie myśli o zmiennych interpunkcyjnych lub zmiennych pakietu.Jeśli sprawdzasz spacje, powinieneś wybrać pomiędzy
\h
i\v
, w zależności od. I nigdy nie powinieneś używać\s
, ponieważ NIE OZNACZA[\h\v]
, wbrew powszechnemu przekonaniu.Jeśli używasz
\n
granicy linii, a nawet\r\n
, robisz to źle. Musisz użyć\R
, co nie jest takie samo!Jeśli nie wiesz, kiedy i czy wywołać Unicode :: Stringprep , lepiej się naucz.
Porównywania bez rozróżniania wielkości liter muszą sprawdzać, czy dwie rzeczy to te same litery, bez względu na ich znaki diakrytyczne i tym podobne. Najłatwiej to zrobić za pomocą standardowego modułu Unicode :: Collate .
Unicode::Collate->new(level => 1)->cmp($a, $b)
. Istnieją równieżeq
metody i takie, i prawdopodobnie powinieneś również dowiedzieć się o metodachmatch
isubstr
. Są to wyraźne zalety w stosunku do wbudowanych 🐪.Czasami to wciąż za mało i zamiast tego potrzebujesz modułu Unicode :: Collate :: Locale
Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)
. UznajUnicode::Collate::->new(level => 1)->eq("d", "ð")
to za prawdę, ale zaUnicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")
fałsz. Podobnie „ae” i „æ” występują,eq
jeśli nie używasz ustawień narodowych lub jeśli używasz języka angielskiego, ale różnią się one w islandzkich ustawieniach regionalnych. Co teraz? To trudne, mówię ci. Możesz grać z ucsort, aby przetestować niektóre z tych rzeczy.Zastanów się, jak dopasować wzór CVCV (konsonsant, samogłoska, spółgłoska, samogłoska) w ciągu „ niño ”. Jego forma NFD, którą lepiej zapamiętałeś, aby ją zapamiętać, staje się „nin \ x {303} o”. Co teraz zamierzasz zrobić? Nawet udając, że samogłoska jest
[aeiou]
(co jest zresztą nie tak), nie będziesz w stanie zrobić czegoś takiego(?=[aeiou])\X)
, ponieważ nawet w NFD punkt kodowy taki jak „ø” nie ulega rozkładowi ! Jednak będzie to test równy „o” przy użyciu porównania UCA, które właśnie pokazałem. Nie możesz polegać na NFD, musisz polegać na UCA.💩 𝔸 𝕤 𝕤 𝕦 𝕞 𝕖 𝔹 𝕣 𝕠 𝕜 𝕖 𝕟 𝕟 𝕖 𝕤 𝕤 💩
I to nie wszystko. Istnieje milion błędnych założeń, które ludzie robią na temat Unicode. Dopóki nie zrozumieją tych rzeczy, ich kod 🐪 zostanie złamany.
Kod, który zakłada, że może otwierać plik tekstowy bez określania kodowania, jest uszkodzony.
Kod, który zakłada, że domyślne kodowanie jest rodzimym kodowaniem platformy jest zepsuty.
Kod, który zakłada, że strony internetowe w języku japońskim lub chińskim zajmują mniej miejsca w UTF ‑ 16 niż w UTF ‑ 8, jest błędny.
Kod, który zakłada, że Perl wewnętrznie używa UTF ‑ 8, jest niepoprawny.
Kod, który zakłada, że błędy kodowania zawsze powodują wyjątek, jest niepoprawny.
Kod, który zakłada, że punkty kodu Perla są ograniczone do 0x10_FFFF, jest niepoprawny.
Kod, który zakłada, że możesz ustawić
$/
coś, co będzie działało z dowolnym poprawnym separatorem linii, jest niepoprawny.Kod, który zakłada równość w obie strony na foldery, podobnie jak
lc(uc($s)) eq $s
lubuc(lc($s)) eq $s
, jest całkowicie uszkodzony i niepoprawny. Weź pod uwagę, że oba sąuc("σ")
iuc("ς")
oba"Σ"
, alelc("Σ")
prawdopodobnie nie mogą zwrócić obu z nich.Kod, który zakłada, że każdy punkt kodu zapisany małymi literami ma wyraźny kod pisany wielkimi literami lub odwrotnie, jest uszkodzony. Na przykład
"ª"
jest małą literą bez wielkich liter; natomiast oba"ᵃ"
i"ᴬ"
są litery, ale nie są one małe litery; jednak oba są małymi punktami kodowymi bez odpowiednich wersji wielkich liter. Zrozumiałeś? Są nie\p{Lowercase_Letter}
, mimo że zarówno\p{Letter}
a\p{Lowercase}
.Kod, który zakłada zmianę wielkości liter, nie zmienia długości łańcucha, jest uszkodzony.
Kod, który zakłada, że są tylko dwa przypadki, jest uszkodzony. Istnieje również titlecase.
Kod, który zakłada, że tylko litery mają wielkość liter, jest uszkodzony. Poza literami okazuje się, że cyfry, symbole, a nawet znaki mają duże litery. W rzeczywistości zmiana sprawy może nawet spowodować zmianę głównej kategorii ogólnej, na przykład
\p{Mark}
przekształcenie w\p{Letter}
. Może także sprawić, że zmieni się z jednego skryptu na inny.Kod, który zakłada, że wielkość liter nigdy nie zależy od ustawień regionalnych, jest uszkodzony.
Kod, który zakłada, że Unicode podaje informację o ustawieniach narodowych POSIX, jest uszkodzony.
Kod, który zakłada, że możesz usunąć znaki diakrytyczne, aby dostać się do podstawowych liter ASCII, jest zły, wciąż uszkodzony, uszkodzony, uszkodzony i usprawiedliwiony karą śmierci.
Kod, który zakłada, że znaki diakrytyczne
\p{Diacritic}
i znaki\p{Mark}
są tym samym, jest łamany.Kod, który zakłada, że
\p{GC=Dash_Punctuation}
obejmuje tyle, ile\p{Dash}
jest zepsuty.Kod, który zakłada myślnik, łączniki i minusy, są takie same, lub że jest tylko jeden, jest zepsuty i zły.
Kod, który zakłada, że każdy punkt kodu nie zajmuje więcej niż jednej kolumny wydruku, jest uszkodzony.
Kod, który zakłada, że wszystkie
\p{Mark}
znaki zajmują zero kolumn drukowania, jest uszkodzony.Kod, który zakłada, że znaki podobne do siebie są podobne, jest łamany.
Kod, który zakłada, że znaki, które nie wyglądają podobnie, nie są identyczne, jest łamany.
Kod, który zakłada, że istnieje ograniczenie liczby punktów kodu w rzędzie, które
\X
można dopasować tylko jeden, jest nieprawidłowy.Kod, który zakłada, że
\X
nigdy nie zaczyna się od\p{Mark}
znaku, jest niepoprawny.Kod, który zakłada, że
\X
nigdy nie może zawierać dwóch\p{Mark}
znaków innych niż, jest niepoprawny.Kod, który zakłada, że nie można go użyć,
"\x{FFFF}"
jest niepoprawny.Kod, który zakłada punkt kodowy inny niż BMP, który wymaga dwóch jednostek kodu UTF-16 (zastępczego), koduje dwa osobne znaki UTF-8, po jednym na jednostkę kodu, jest niepoprawny. Nie: koduje do pojedynczego punktu kodowego.
Kod transkodujący z UTF ‐ 16 lub UTF ‐ 32 z wiodącymi BOM do UTF ‐ 8 jest uszkodzony, jeśli umieści BOM na początku wynikowego UTF-8. To takie głupie, że inżynier powinien mieć zdjęte powieki.
Kod, który zakłada, że CESU-8 jest prawidłowym kodowaniem UTF, jest niepoprawny. Podobnie kod, który myśli o kodowaniu U + 0000, podobnie jak
"\xC0\x80"
UTF-8, jest uszkodzony i niepoprawny. Ci faceci również zasługują na leczenie powiekami.Kod, który zakłada, że znaki jak
>
zawsze wskazuje na prawo i<
zawsze wskazuje na lewą stronę, są błędne - ponieważ w rzeczywistości tak nie jest.Kod, który zakłada, że jeśli najpierw wypiszesz znak,
X
a następnie znakY
, że będą one wyświetlane jakoXY
nieprawidłowe. Czasem nie.Kod, który zakłada, że ASCII jest wystarczający do poprawnego pisania po angielsku, jest głupi, krótkowzroczny, niepiśmienny, łamany, zły i zły. Precz z głowami! Jeśli wydaje się to zbyt ekstremalne, możemy pójść na kompromis: odtąd mogą pisać tylko dużym palcem z jednej stopy. (Reszta zostanie nagrana taśmą klejącą.)
Kod, który zakłada, że wszystkie
\p{Math}
punkty kodu są widocznymi znakami, jest niepoprawny.Zakładany kod
\w
zawiera tylko litery, cyfry i podkreślenia jest niepoprawny.Kod, który zakłada, że
^
i~
są znaki przestankowe jest źle.Kod, który zakłada, że
ü
ma umlaut, jest niepoprawny.Kod, który uważa, że takie rzeczy
₨
zawierają jakiekolwiek litery, jest niepoprawny.Kod, który wierzy,
\p{InLatin}
jest taki sam, jak\p{Latin}
potwornie złamany.Kod, który uważa, że
\p{InLatin}
jest prawie zawsze przydatny, prawie na pewno jest zły.Kod, który uważa, że podany
$FIRST_LETTER
jako pierwsza litera w jakimś alfabecie i$LAST_LETTER
jako ostatnia litera w tym samym alfabecie, który[${FIRST_LETTER}-${LAST_LETTER}]
ma jakiekolwiek znaczenie, prawie zawsze jest całkowicie zepsuty, zły i bez znaczenia.Kod, który uważa, że czyjeś imię może zawierać tylko niektóre znaki, jest głupi, obraźliwy i niewłaściwy.
Kod, który próbuje zredukować Unicode do ASCII, nie jest po prostu zły, jego sprawca nigdy nie powinien mieć możliwości ponownego programowania. Kropka. Nie jestem nawet pewna, czy powinno się im znowu pozwolić zobaczyć, ponieważ jak dotąd nie przyniosło to im wiele dobrego.
Kod, który uważa, że istnieje jakiś sposób udawania, że kodowanie plików tekstowych nie istnieje, jest uszkodzony i niebezpieczny. Równie dobrze może wystawić drugie oko.
Kod, który zamienia nieznane znaki,
?
jest zepsuty, głupi, braindead i działa wbrew standardowej rekomendacji, która mówi: NIE NALEŻY TO ROBIĆ!RTFM, dlaczego nie.Kod, który uważa, że może niezawodnie odgadnąć kodowanie nieoznaczonego pliku tekstowego, jest winny fatalnej melanżu pychy i naiwności, którą naprawi tylko błyskawica Zeusa.
Kod, który uważa, że możesz użyć 🐪
printf
szerokości do wypełniania i uzasadniania danych Unicode, jest uszkodzony i niepoprawny.Kod, który wierzy, że po pomyślnym utworzeniu pliku o danej nazwie, że po uruchomieniu
ls
lubreaddir
w jego zamkniętym katalogu faktycznie znajdziesz ten plik pod nazwą, pod którą go utworzyłeś, jest wadliwy, uszkodzony i niewłaściwy. Przestań być tym zaskoczony!Kod, który uważa, że UTF-16 jest kodowaniem o stałej szerokości, jest głupi, uszkodzony i niewłaściwy. Odwołaj ich licencję na programowanie.
Kod, który traktuje punkty kodu z jednej płaszczyzny jeden odrobinę inaczej niż te z innej płaszczyzny, jest ipso facto uszkodzony i zły. Wracaj do szkoły.
Kod, który uważa, że takie rzeczy
/s/i
mogą tylko pasować"S"
lub"s"
są zepsute i złe. Zdziwiłbyś się.Kod używany
\PM\pM*
do znajdowania klastrów grafemów zamiast używania\X
jest uszkodzony i niepoprawny.Ludzie, którzy chcą wrócić do świata ASCII, powinni być do tego szczerze zachęcani, a na ich chwalebne ulepszenie powinni otrzymać bezpłatnie elektryczną maszynę do pisania spełniającą wszystkie potrzeby w zakresie wprowadzania danych. Wiadomości wysyłane do nich powinny być wysyłane telegrafem w ilości 40 znaków na linię i dostarczane ręcznie przez kuriera. ZATRZYMAĆ.
😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 😱
Nie wiem, o ile więcej „domyślnego Unicode w 🐪” można uzyskać, niż to, co napisałem. Cóż, tak, mam: powinieneś używać
Unicode::Collate
iUnicode::LineBreak
. I prawdopodobnie więcej.Jak widać, nie ma zbyt wiele rzeczy, Unicode, że naprawdę nie trzeba się martwić o tam na zawsze istnieje coś takiego jak „domyślnie do Unicode”.
Co odkryjesz, tak jak to zrobiliśmy w 🐪 5.8, że po prostu nie można narzucić tych wszystkich rzeczy na kod, który nie został zaprojektowany od samego początku, aby je uwzględnić. Wasze dobre intencje egoizm właśnie rozbił cały świat.
Nawet jeśli to zrobisz, nadal istnieją problemy krytyczne, które wymagają wiele przemyślenia, aby rozwiązać problem. Nie ma przełącznika, który można przerzucić. Wystarczy mózg, a mam na myśli prawdziwy mózg . Jest mnóstwo rzeczy, których musisz się nauczyć. Modulo wycofanie się do ręcznej maszyny do pisania, po prostu nie możesz mieć nadziei, że będziesz się wymykał w nieświadomości. Jest to 21ˢᵗ wiek i nie możesz życzyć Unicode umyślnej ignorancji.
Musisz się tego nauczyć. Kropka. To nigdy nie będzie tak łatwe, że „wszystko po prostu działa”, ponieważ gwarantuje to, że wiele rzeczy nie działa działało działa - co unieważnia założenie, że może istnieć sposób, aby „wszystko działało”.
Możesz uzyskać kilka rozsądnych ustawień domyślnych dla bardzo niewielu i bardzo ograniczonych operacji, ale nie bez myślenia o rzeczach o wiele bardziej niż myślę, że masz.
Jako jeden przykład, porządek kanoniczny spowoduje pewne bóle głowy. 😭
"\x{F5}"
„õ” ,"o\x{303}"
„õ” ,"o\x{303}\x{304}"
„ȭ” i"o\x{304}\x{303}"
„ō̃” powinny pasować do „õ” , ale jak, u licha , zamierzacie to zrobić? Jest to trudniejsze niż się wydaje, ale należy się z tym pogodzić. 💣Jeśli jest coś, co wiem o Perlu, to to, co robią jego bity Unicode, a czego nie, i obiecuję ci: „̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲” 😞
Nie możesz po prostu zmienić niektórych ustawień domyślnych i uzyskać płynnej żeglugi. To prawda, że uruchamiam 🐪 z
PERL_UNICODE
ustawionym na"SA"
, ale to wszystko, a nawet to dotyczy głównie wiersza poleceń. W prawdziwej pracy przechodzę przez wszystkie opisane powyżej kroki i robię to bardzo, ** bardzo ** ostrożnie.😈 ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʻʞɔnl poo⅁ 😈
źródło
Istnieją dwa etapy przetwarzania tekstu Unicode. Pierwszym z nich jest „jak mogę go wprowadzić i wyprowadzić bez utraty informacji”. Drugi to „jak traktować tekst zgodnie z lokalnymi konwencjami językowymi”.
Post tchrista obejmuje oba te elementy, ale druga część to 99% tekstu jego postu. Większość programów nawet nie obsługuje poprawnie I / O, dlatego ważne jest, aby zrozumieć, że zanim zaczniesz martwić się o normalizację i zestawianie.
Ten post ma na celu rozwiązanie tego pierwszego problemu
Kiedy wczytujesz dane do Perla, nie ma znaczenia, jakie to kodowanie. Przydziela część pamięci i chowa tam bajty. Jeśli powiesz
print $str
, po prostu przenosi te bajty do twojego terminala, który prawdopodobnie jest ustawiony tak, aby zakładać, że wszystko, co jest w nim zapisane, to UTF-8, a twój tekst się pojawi.Cudowny.
Tyle że nie. Jeśli spróbujesz traktować dane jako tekst, zobaczysz, że dzieje się coś złego. Nie musisz iść dalej niż
length
zobaczyć, co Perl myśli o twoim sznurku i co myślisz o sznurku się nie zgadza. Napisz jedno linijkę, taką jak:perl -E 'while(<>){ chomp; say length }'
i wpisz,文字化け
a otrzymasz 12 ... nieprawidłowa odpowiedź, 4.To dlatego, że Perl zakłada, że twój ciąg nie jest tekstem. Musisz powiedzieć, że to tekst, zanim da ci właściwą odpowiedź.
To dość łatwe; moduł Encode ma do tego odpowiednie funkcje. Ogólny punkt wejścia to
Encode::decode
(lubuse Encode qw(decode)
oczywiście). Ta funkcja pobiera ciąg znaków ze świata zewnętrznego (to, co nazwiemy „oktetami”, wymyślny sposób na powiedzenie „8-bitowych bajtów”), i zamienia go w tekst, który Perl zrozumie. Pierwszy argument to nazwa kodująca znak, na przykład „UTF-8” lub „ASCII” lub „EUC-JP”. Drugi argument to ciąg. Zwracana wartość to skalar Perl zawierający tekst.(Jest też
Encode::decode_utf8
, który zakłada kodowanie UTF-8).Jeśli przepiszemy jedną linijkę:
Wpisujemy 文字 化 け i otrzymujemy „4” jako wynik. Sukces.
To właśnie jest rozwiązanie 99% problemów z Unicode w Perlu.
Kluczem jest to, że za każdym razem, gdy jakiś tekst pojawia się w twoim programie, musisz go odkodować. Internet nie może przesyłać znaków. Pliki nie mogą przechowywać znaków. W bazie danych nie ma znaków. Są tylko oktety i nie można traktować oktetów jako znaków w Perlu. Musisz zdekodować zakodowane oktety na znaki Perla za pomocą modułu Encode.
Druga połowa problemu to pobieranie danych z programu. To łatwe; po prostu mówisz
use Encode qw(encode)
, zdecyduj, w jakim kodowaniu będą twoje dane (UTF-8 do terminali, które rozumieją UTF-8, UTF-16 dla plików w systemie Windows itp.), a następnie wypisz wynikencode($encoding, $data)
zamiast po prostu wypisywać$data
.Ta operacja przekształca znaki Perla, na których działa Twój program, w oktety, które mogą być używane przez świat zewnętrzny. Byłoby o wiele łatwiej, gdybyśmy mogli po prostu wysyłać znaki przez Internet lub do naszych terminali, ale nie możemy: tylko oktety. Musimy więc przekonwertować znaki na oktety, w przeciwnym razie wyniki nie zostaną zdefiniowane.
Podsumowując: zakoduj wszystkie wyjścia i odkoduj wszystkie wejścia.
Teraz porozmawiamy o trzech kwestiach, które sprawiają, że jest to trochę trudne. Pierwsza to biblioteki. Czy poprawnie obsługują tekst? Odpowiedź brzmi ... próbują. Jeśli pobierzesz stronę internetową, LWP zwróci ci wynik jako tekst. Jeśli wywołasz odpowiednią metodę w wyniku, to znaczy (i tak się składa
decoded_content
, że niecontent
, to tylko strumień oktetów, który otrzymał z serwera). Sterowniki bazy danych mogą być niestabilne; jeśli użyjesz DBD :: SQLite tylko z Perlem, to zadziała, ale jeśli jakieś inne narzędzie umieściło w bazie danych tekst zapisany jako kodowanie inne niż UTF-8 ... cóż ... to nie będzie poprawnie obsługiwane dopóki nie napiszesz kodu, aby poprawnie go obsłużyć.Wyprowadzanie danych jest zwykle łatwiejsze, ale jeśli widzisz „szeroki znak w druku”, to wiesz, że gdzieś psujesz kodowanie. To ostrzeżenie oznacza „hej, próbujesz wyciec postacie Perla do świata zewnętrznego i to nie ma żadnego sensu”. Twój program wydaje się działać (ponieważ drugi koniec zwykle poprawnie obsługuje nieprzetworzone znaki Perla), ale jest bardzo zepsuty i może przestać działać w dowolnym momencie. Napraw to wyraźnie
Encode::encode
!Drugi problem to kod źródłowy zakodowany w UTF-8. O ile nie powiesz
use utf8
na górze każdego pliku, Perl nie przyjmie, że kod źródłowy to UTF-8. Oznacza to, że za każdym razem, gdy mówisz coś takiegomy $var = 'ほげ'
, wstrzykujesz śmieci do swojego programu, który całkowicie psuje wszystko okropnie. Nie musisz „używać utf8”, ale jeśli nie, to należy nie używać żadnych znaków spoza ASCII w swoim programie.Trzeci problem dotyczy tego, jak Perl radzi sobie z przeszłością. Dawno temu nie było czegoś takiego jak Unicode, a Perl założył, że wszystko jest tekstem Latin-1 lub binarnym. Więc kiedy dane przychodzą do twojego programu i zaczynasz traktować je jak tekst, Perl traktuje każdy oktet jako znak Latin-1. Właśnie dlatego, gdy poprosiliśmy o długość „文字 化 け”, otrzymaliśmy 12. Perl założył, że działamy na łańcuchu Latin-1 „æååã” (który ma 12 znaków, z których niektóre nie są drukowane).
Nazywa się to „niejawnym uaktualnieniem” i jest to całkowicie rozsądne, ale nie jest to pożądane, jeśli tekst nie jest w języku łacińskim-1. Dlatego tak ważne jest jawne odkodowanie danych wejściowych: jeśli tego nie zrobisz, Perl zrobi to i może zrobić to źle.
Ludzie wpadają w kłopoty, gdy połowa ich danych to ciąg znaków, a niektóre nadal są binarne. Perl zinterpretuje część, która wciąż jest binarna, tak jakby to był tekst Latin-1, a następnie połączy ją z poprawnymi danymi znakowymi. To sprawi, że będzie wyglądało na to, że prawidłowe zarządzanie postaciami zepsuło twój program, ale w rzeczywistości po prostu nie naprawiłeś go wystarczająco.
Oto przykład: masz program, który czyta plik tekstowy zakodowany w UTF-8, wstawiasz Unicode
PILE OF POO
do każdej linii i drukujesz go. Piszecie tak:Następnie uruchom niektóre dane zakodowane w UTF-8, takie jak:
Drukuje dane UTF-8 ze kupką na końcu każdej linii. Idealnie, mój program działa!
Ale nie, po prostu robisz binarną konkatenację. Czytasz oktety z pliku, usuwasz
\n
z chomp, a następnie dodajesz bajty w reprezentacjiPILE OF POO
znaku UTF-8 . Kiedy poprawisz swój program, aby zdekodować dane z pliku i zakodować dane wyjściowe, zauważysz, że zamiast śmieci kupujesz śmieci („ð ©”). Doprowadzi cię to do przekonania, że dekodowanie pliku wejściowego jest niewłaściwe. To nie jest.Problem polega na tym, że kupa jest domyślnie aktualizowana jako latin-1. Jeśli
use utf8
utworzysz dosłowny tekst zamiast binarny, to znowu zadziała!(To jest problem numer jeden, który widzę, gdy pomagam ludziom z Unicode. Rozstali się dobrze i to zepsuło ich program. To jest smutne z powodu nieokreślonych wyników: możesz mieć działający program przez długi czas, ale kiedy zaczniesz go naprawiać, psuje się. Nie martw się; jeśli dodajesz do swojego programu instrukcje kodowania / dekodowania i psuje się, oznacza to, że masz więcej pracy do zrobienia. Następnym razem, kiedy projektujesz z myślą o Unicode od samego początku, będzie to dużo łatwiej!)
To naprawdę wszystko, co musisz wiedzieć o Perlu i Unicode. Jeśli powiesz Perlowi, jakie są twoje dane, ma najlepszą obsługę Unicode spośród wszystkich popularnych języków programowania. Jeśli zakładasz, że magicznie będzie wiedział, jaki rodzaj tekstu podajesz, to nieodwracalnie usuniesz swoje dane. To, że Twój program działa dzisiaj na terminalu UTF-8, nie oznacza, że będzie działać jutro na pliku zakodowanym w UTF-16. Więc teraz to bezpieczne i oszczędzaj sobie kłopotów z usuwaniem danych użytkowników!
Łatwą częścią obsługi Unicode jest kodowanie danych wyjściowych i dekodowanie danych wejściowych. Trudność polega na znalezieniu wszystkich danych wejściowych i wyjściowych oraz ustaleniu, jakie to kodowanie. Ale dlatego dostajesz duże pieniądze :)
źródło
Encode
modułu jest żmudne i podatne na błędy, co sprawia, że czytanie kodu dotyczącego operacji we / wy jest bardzo bolesne. Warstwy we / wy zapewniają rozwiązanie, ponieważ w razie potrzeby transparentnie kodują i dekodują.open
ibinmode
pozwalają na ich specyfikację, a pragmaopen
określa wartości domyślne, jak zalecił tchrist w swojej odpowiedzi.Wszyscy zgadzamy się, że jest to trudny problem z wielu powodów, ale właśnie dlatego staramy się ułatwić wszystkim.
Istnieje najnowszy moduł CPAN, utf8 :: all , który próbuje „włączyć Unicode. Wszystko”.
Jak już wspomniano, nie można magicznie sprawić, aby cały system (programy zewnętrzne, zewnętrzne żądania sieciowe itp.) Również używał Unicode, ale możemy współpracować, aby tworzyć rozsądne narzędzia, które ułatwiają wykonywanie typowych problemów. Właśnie dlatego jesteśmy programistami.
Jeśli utf8 :: all nie robi czegoś, co według ciebie powinno, poprawmy to, aby było lepiej. Lub stwórzmy dodatkowe narzędzia, które razem mogą jak najlepiej odpowiadać na różne potrzeby ludzi.
`
źródło
utf8::all
module. Został napisany przedunicode_strings
funkcją, którą Fɪɴᴀʟʟʏ ᴀɴᴅ ᴀᴛ Lᴏɴɢ Lᴀsᴛ naprawia wyrażenia regularne, aby je mieć/u
. Nie jestem przekonany, że rodzi to wyjątek dotyczący błędów kodowania i jest to coś, co naprawdę musisz mieć. Nie ładuje się wuse charnames ":full"
pragmie, która nie jest jeszcze automatycznie ładowana. Nie ostrzega o[a-z]
takichprintf
szerokościach znaków, używając\n
zamiast\R
i.
zamiast\X
, ale może to bardziejPerl::Critic
kwestia. Gdybym to był ja, dodałbym 𝐍𝐅𝐃 in and out.unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r
. Podobnie, małe kroki przygotowawcze, takie jak,... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'
mogą być naprawdę miłe i nie chciałbym podejmować za nich decyzji innych. Wciąż buduję zestaw narzędzi Unicode .Myślę, że źle rozumiesz Unicode i jego związek z Perlem. Bez względu na to, w jaki sposób przechowujesz dane, Unicode, ISO-8859-1 lub wiele innych rzeczy, twój program musi wiedzieć, jak interpretować bajty, które otrzymuje jako dane wejściowe (dekodowanie) i jak reprezentować informacje, które chce wyprowadzić (kodowanie) ). Błędnie zinterpretuj tę interpretację, a będziesz marnować dane. W twoim programie nie ma żadnej magicznej domyślnej konfiguracji, która powiedziałaby osobom spoza programu, jak się zachować.
Myślisz, że to trudne, najprawdopodobniej, ponieważ jesteś przyzwyczajony do wszystkiego, co ASCII. Wszystko, o czym powinieneś pomyśleć, zostało po prostu zignorowane przez język programowania i wszystkie rzeczy, z którymi musiał wchodzić w interakcje. Gdyby wszystko wykorzystywało tylko UTF-8 i nie miałeś wyboru, to UTF-8 byłoby równie łatwe. Ale nie wszystko korzysta z UTF-8. Na przykład, nie chcesz, aby Twój uchwyt wejściowy myślał, że pobiera oktety UTF-8, chyba że tak naprawdę jest, i nie chcesz, aby twoje uchwyty wyjściowe były UTF-8, jeśli odczyt z nich może obsłużyć UTF-8 . Perl nie ma sposobu, aby poznać te rzeczy. Dlatego jesteś programistą.
Nie sądzę, aby Unicode w Perlu 5 był zbyt skomplikowany. Myślę, że to przerażające i ludzie tego unikają. Jest różnica. W tym celu umieściłem Unicode w Learning Perl, 6. edycja , i jest wiele rzeczy w Unicode w Effective Perl Programming . Musisz poświęcić czas na naukę i zrozumienie Unicode oraz jego działania. W przeciwnym razie nie będziesz w stanie efektywnie z niego korzystać.
źródło
use utf8_everywhere
ludzie są szczęśliwi. Dlaczego nie ostatni?Czytając ten wątek, często mam wrażenie, że ludzie używają „ UTF-8 ” jako synonimu „ Unicode ”. Dokonaj rozróżnienia między „punktami kodowymi” Unicode, które są powiększonymi krewnymi kodu ASCII, a różnymi „kodowaniami” Unicode. Jest ich kilka, w tym UTF-8, UTF-16 i UTF-32 , a kilka innych jest przestarzałych.
Proszę, UTF-8 (jak również wszystkie inne kodowania ) istnieje i ma znaczenie tylko na wejściu lub wyjściu. Wewnętrznie od wersji 5.8.1 wszystkie ciągi znaków są przechowywane jako „punkty kodowe” w standardzie Unicode. To prawda, że musisz włączyć niektóre funkcje, które wcześniej były podziwiane.
źródło
Na wolności jest naprawdę przerażająca ilość starożytnego kodu, w dużej mierze w postaci wspólnych modułów CPAN. Odkryłem, że muszę dość ostrożnie włączać Unicode, jeśli korzystam z zewnętrznych modułów, na które może mieć wpływ, i nadal próbuję zidentyfikować i naprawić niektóre błędy związane z Unicode w kilku skryptach Perla, których regularnie używam (w szczególności iTiVo nie działa źle na wszystkim, co nie jest 7-bitowym ASCII z powodu problemów z transkodowaniem).
źródło
-C
opcji, aby upewnić się, że Perl jest na tej samej stronie, co ja, jeśli chodzi o Unicode, ponieważ wciąż decyduję się na użycie ISO 8859/1 zamiast Unicode, mimo że jawnie ustawiam$LANG
i$LC_ALL
poprawnie. (Może to faktycznie odzwierciedlać błędy w bibliotekach regionalnych platformy.) Cokolwiek to jest, bardzo denerwujące jest to, że nie mogę używać iTivo w programach z akcentami, ponieważ skrypty Perla, które wykonują pracę, przewracają się z błędami konwersji.-C
bez opcji jest podatny na błędy i błędy . Rozbijasz świat. UstawPERL5OPT
zmienną na,-C
a zobaczysz, co mam na myśli. Próbowaliśmy tego w wersji v8.8 i była to katastrofa. Po prostu nie możesz i nie wolno informować programów, które się tego nie spodziewają, że teraz mają do czynienia z Unicode, czy im się to podoba, czy nie. Istnieją również problemy z bezpieczeństwem. Przynajmniej wszystko, coprint while <>
się zepsuje, jeśli zostaną przekazane dane binarne. Podobnie będzie z całym kodem bazy danych. To okropny pomysł.-C
bez opcji. Konkretne wywołanie, z którym pracowałem, to-CSDA
. To powiedziawszy, utknąłem z 5.8.x przez długi czas (cześć MacPorts ...), więc może to było częścią tego.Powinieneś włączyć funkcję ciągów znaków Unicode, a jest to ustawienie domyślne, jeśli używasz v5.14;
Naprawdę nie powinieneś używać identyfikatorów Unicode esp. dla obcego kodu za pośrednictwem utf8, ponieważ nie są one bezpieczne w perl5, tylko cperl miał to poprawnie. Zobacz np. Http://perl11.org/blog/unicode-identifiers.html
Odnośnie utf8 dla twoich uchwytów / strumieni plików: Musisz sam zdecydować o kodowaniu swoich danych zewnętrznych. Biblioteka nie może tego wiedzieć, a ponieważ nawet libc nie obsługuje utf8, prawidłowe dane utf8 są rzadkie. Wokół jest więcej wtf8, aberracja systemu Windows w utf8.
BTW: Łoś nie jest tak naprawdę „Modern Perl”, po prostu porwał nazwę. Łoś jest idealny postmodernistyczny perl w stylu Larry'ego Walla i wszystko w stylu Bjarne Stroustrup, z eklektyczną aberracją właściwej składni perl6, np. Używając ciągów znaków dla zmiennych nazw, składni strasznych pól i bardzo niedojrzałej naiwnej implementacji, która jest 10 razy wolniejsza niż prawidłowe wdrożenie. cperl i perl6 są prawdziwymi nowoczesnymi perlami, w których forma podąża za funkcją, a implementacja jest ograniczona i zoptymalizowana.
źródło