Mengapa Perl modern menghindari UTF-8 secara default?

557

Saya bertanya-tanya mengapa sebagian besar solusi modern yang dibangun menggunakan Perl tidak mengaktifkan UTF-8 secara default.

Saya mengerti ada banyak masalah warisan untuk skrip Perl inti, di mana ia dapat merusak banyak hal. Tapi, dari sudut pandang saya, dalam 21 st abad, proyek-proyek baru yang besar (atau proyek dengan perspektif besar) harus membuat perangkat lunak mereka UTF-8 bukti dari awal. Tetap saya tidak melihat itu terjadi. Misalnya, Moose mengaktifkan peringatan ketat dan, tetapi tidak Unicode . Modern :: Perl juga mengurangi boilerplate, tetapi tidak ada penanganan UTF-8.

Mengapa? Apakah ada beberapa alasan untuk menghindari UTF-8 dalam proyek Perl modern di tahun 2011?


Mengomentari @tchrist terlalu lama, jadi saya menambahkannya di sini.

Sepertinya saya tidak membuat diri saya jelas. Izinkan saya mencoba menambahkan beberapa hal.

tchrist dan saya melihat situasi yang serupa, tetapi kesimpulan kami sepenuhnya bertolak belakang. Saya setuju, situasi dengan Unicode rumit, tapi ini sebabnya kami (pengguna Perl dan coders) membutuhkan beberapa lapisan (atau pragma) yang membuat penanganan UTF-8 semudah seperti yang seharusnya saat ini.

tchrist menunjuk ke banyak aspek untuk dibahas, saya akan membaca dan memikirkannya selama berhari-hari atau bahkan berminggu-minggu. Tetap saja, ini bukan poin saya. tchrist mencoba membuktikan bahwa tidak ada satu cara "untuk mengaktifkan UTF-8". Saya tidak memiliki banyak pengetahuan untuk membantahnya. Jadi, saya tetap berpegang pada contoh hidup.

Saya bermain-main dengan Rakudo dan UTF-8 ada di sana sesuai kebutuhan saya . Saya tidak punya masalah, itu hanya berhasil. Mungkin ada beberapa batasan di suatu tempat yang lebih dalam, tetapi pada awalnya, semua yang saya uji berhasil seperti yang saya harapkan.

Bukankah itu seharusnya menjadi tujuan dalam Perl 5 modern juga? Saya lebih menekankan: Saya tidak menyarankan UTF-8 sebagai karakter default yang ditetapkan untuk core Perl, saya menyarankan kemungkinan untuk memicunya dengan snap bagi mereka yang mengembangkan proyek baru .

Contoh lain, tetapi dengan nada yang lebih negatif. Kerangka kerja harus membuat pengembangan lebih mudah. Beberapa tahun yang lalu, saya mencoba kerangka kerja web, tetapi hanya membuangnya karena "mengaktifkan UTF-8" begitu tidak jelas. Saya tidak menemukan bagaimana dan di mana menghubungkan dukungan Unicode. Sangat memakan waktu sehingga saya merasa lebih mudah untuk pergi dengan cara lama. Sekarang saya melihat di sini ada karunia untuk menangani masalah yang sama dengan Mason 2: Bagaimana cara membuat Mason2 UTF-8 bersih? . Jadi, ini adalah kerangka kerja yang cukup baru, tetapi menggunakannya dengan UTF-8 membutuhkan pengetahuan mendalam tentang internalnya. Itu seperti tanda merah besar: BERHENTI, jangan gunakan aku!

Saya sangat suka Perl. Tetapi berurusan dengan Unicode itu menyakitkan. Saya masih menemukan diri saya berlari melawan tembok. Beberapa cara tchrist benar dan menjawab pertanyaan saya: proyek baru tidak menarik UTF-8 karena terlalu rumit dalam Perl 5.

minggu
sumber
15
Maaf, tapi saya setuju dengan @tchrist - UTF-8 sangat sulit. Tidak ada kerangka atau alat yang hanya "membalik saklar" dan kemudian menanganinya dengan benar. Ini adalah sesuatu yang harus Anda pikirkan secara langsung ketika mendesain aplikasi Anda - bukan sesuatu yang bisa ditangani oleh kerangka kerja atau bahasa apa pun untuk Anda. Jika rakudo kebetulan bekerja untuk Anda, Anda tidak cukup berani dengan kasus uji Anda - karena akan mengambil beberapa contoh dalam jawaban @tchrist dan tukang daging kemudian.
Billy ONeal
12
Apa yang sebenarnya Anda harapkan dari Moose atau Modern :: Perl? Ajaibnya membuat data karakter yang disandikan secara acak dalam file dan basis data menjadi data yang valid lagi?
jrockway
13
Apa artinya? Moose tidak ada hubungannya dengan manipulasi teks. Mengapa harus tahu tentang pengkodean karakter, apalagi memilih yang default untuk Anda? (Omong-omong, alasan mengapa pragma yang Anda daftarkan tidak menyentuh pengkodean adalah karena konvensi ini untuk pragma Perl untuk memengaruhi perilaku leksikal . Dengan asumsi bahwa Seluruh Dunia, modul-modul lain yang disertakan, adalah UTF-8 hanyalah hal yang salah untuk dilakukan Ini bukan PHP atau Ruby di sini.)
jrockway
8
(Juga ... "sebagian besar aplikasi Perl Modern" berhenti di UTF-8? Saya pasti tidak pernah menulis aplikasi, Perl atau yang lainnya, itu bukan Unicode-clean.)
jrockway
11
Nb. tchrist (Tom Christiansen) memposting [ training.perl.com/OSCON2011/index.html Tom Christiansen untuk OSCON 2011] tentang Unicode. Yang berjudul "Unicode Support Shootout: The Good, The Bad, & the (kebanyakan) Ugly" berbicara tentang dukungan Unicode dalam berbagai bahasa pemrograman. Hanya Google Go dan Perl5 yang memiliki dukungan untuk Unicode penuh, hanya Google Go builtin (tidak disebutkan Perl6).
Jakub Narฤ™bski

Jawaban:

1146

๐™Ž๐™ž๐™ข๐™ฅ๐™ก๐™š๐™จ๐™ฉ โ„ž : ๐Ÿ• ๐˜ฟ๐™ž๐™จ๐™˜๐™ง๐™š๐™ฉ๐™š ๐™๐™š๐™˜๐™ค๐™ข๐™ข๐™š๐™ฃ๐™™๐™–๐™ฉ๐™ž๐™ค๐™ฃ๐™จ

  1. Atur PERL_UNICODEenvariable Anda menjadi AS. Ini membuat semua skrip Perl didekode @ARGVsebagai string UTF โ€‘ 8, dan menetapkan pengodean ketiga stdin, stdout, dan stderr ke UTF 8. Keduanya adalah efek global, bukan yang leksikal.

  2. Di bagian atas file sumber Anda (program, modul, perpustakaan, docupang), dengan tegas menyatakan bahwa Anda menjalankan perl versi 5.12 atau lebih baik melalui:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
  3. Aktifkan peringatan, karena deklarasi sebelumnya hanya memungkinkan penyempitan dan fitur, bukan peringatan. Saya juga menyarankan untuk mempromosikan peringatan Unicode ke dalam pengecualian, jadi gunakan kedua baris ini, bukan hanya satu saja. Catatan namun yang di bawah v5.14, yang utf8kelas peringatan terdiri dari tiga subwarnings lain yang semua bisa secara terpisah diaktifkan: nonchar, surrogate, dan non_unicode. Ini Anda mungkin ingin melakukan kontrol yang lebih besar.

    use warnings;
    use warnings qw( FATAL utf8 );
  4. Nyatakan bahwa unit sumber ini dikodekan sebagai UTF โ€‘ 8. Walaupun suatu ketika pragma ini melakukan hal-hal lain, pragma ini melayani satu tujuan tunggal dan tidak lain:

    use utf8;
  5. Menyatakan bahwa apa pun yang membuka filehandle dalam lingkup leksikal ini tetapi tidak di tempat lain adalah dengan menganggap bahwa stream dikodekan dalam UTF-8 kecuali Anda memberi tahu sebaliknya. Dengan begitu Anda tidak memengaruhi modul lain atau kode program lain.

    use open qw( :encoding(UTF-8) :std );
  6. Aktifkan karakter bernama melalui \N{CHARNAME}.

    use charnames qw( :full :short );
  7. Jika Anda memiliki DATApegangan, Anda harus secara eksplisit mengatur penyandiannya. Jika Anda ingin ini menjadi UTF โ€‘ 8, maka katakan:

    binmode(DATA, ":encoding(UTF-8)");

Tentu saja tidak ada akhir dari masalah lain yang akhirnya membuat Anda khawatir, tetapi ini sudah cukup untuk mendekati tujuan negara untuk "membuat semuanya bekerja dengan UTF-8", meskipun untuk pengertian istilah-istilah tersebut agak melemah.

Satu pragma lain, meskipun tidak terkait Unicode, adalah:

      use autodie;

Sangat disarankan.

๐ŸŒด ๐Ÿช๐Ÿซ๐Ÿช ๐ŸŒž ๐•ฒ๐–” ๐•ฟ๐–๐–”๐–š ๐–†๐–“๐–‰ ๐•ฏ๐–” ๐•ท๐–Ž๐–๐–Š๐–œ๐–Ž๐–˜๐–Š ๐•ท๐–Ž๐–๐–Š๐–œ๐–Ž๐–˜๐–Š ๐ŸŒž ๐Ÿ


๐ŸŽ ๐Ÿช ๐•ญ๐–”๐–Ž๐–‘๐–Š๐–—โธ—๐–•๐–‘๐–†๐–™๐–Š ๐–‹๐–”๐–— ๐–€๐–“๐–Ž๐–ˆ๐–”๐–‰๐–Šโธ—๐•ฌ๐–œ๐–†๐–—๐–Š ๐•ฎ๐–”๐–‰๐–Š ๐Ÿช ๐ŸŽ


Ketel uap saya sendiri akhir-akhir ini cenderung terlihat seperti ini:

use 5.014;

use utf8;
use strict;
use autodie;
use warnings; 
use warnings    qw< FATAL  utf8     >;
use open        qw< :std  :utf8     >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use File::Basename      qw< basename >;
use Carp                qw< carp croak confess cluck >;
use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

END { close STDOUT }

if (grep /\P{ASCII}/ => @ARGV) { 
   @ARGV = map { decode("UTF-8", $_) } @ARGV;
}

$0 = basename($0);  # shorter messages
$| = 1;

binmode(DATA, ":utf8");

# give a full stack dump on any untrapped exceptions
local $SIG{__DIE__} = sub {
    confess "Uncaught exception: @_" unless $^S;
};

# now promote run-time warnings into stack-dumped
#   exceptions *unless* we're in an try block, in
#   which case just cluck the stack dump instead
local $SIG{__WARN__} = sub {
    if ($^S) { cluck   "Trapped warning: @_" } 
    else     { confess "Deadly warning: @_"  }
};

while (<>)  {
    chomp;
    $_ = NFD($_);
    ...
} continue {
    say NFC($_);
}

__END__

๐ŸŽ… ๐•น ๐–” ๐•ธ ๐–† ๐–Œ ๐–Ž ๐–ˆ ๐–ˆ ๐•ญ ๐–‘ ๐–‘ ๐–‘ ๐–Š ๐–™ ๐ŸŽ…


Mengatakan bahwa โ€œPerl harus [ entah bagaimana! ] aktifkan Unicode secara default โ€bahkan tidak mulai berpikir untuk menyiasati untuk mengatakan cukup bahkan sedikit berguna dalam beberapa kasus langka dan terisolasi. Unicode jauh lebih dari sekadar repertoar karakter yang lebih besar; tetapi juga bagaimana semua karakter itu berinteraksi dalam banyak cara.

Bahkan tindakan minimal yang berpikiran sederhana yang (beberapa) orang tampaknya berpikir mereka inginkan dijamin akan menghancurkan jutaan baris kode, kode yang tidak memiliki kesempatan untuk "meningkatkan" ke Dunia Baru Anda yang baru dan berani. modernitas .

Ini adalah cara yang jauh lebih rumit daripada yang dilakukan orang. Saya sudah memikirkan hal ini, banyak sekali selama beberapa tahun terakhir. Saya ingin ditunjukkan bahwa saya salah. Tapi saya rasa saya tidak. Unicode pada dasarnya lebih kompleks daripada model yang Anda ingin memaksakan padanya, dan ada kompleksitas di sini bahwa Anda tidak pernah bisa menyapu di bawah karpet. Jika Anda mencoba, Anda akan merusak kode Anda sendiri atau orang lain. Pada titik tertentu, Anda hanya perlu memecah dan mempelajari tentang apa itu Unicode. Anda tidak bisa berpura-pura itu sesuatu yang bukan.

๐Ÿช berusaha keras untuk membuat Unicode mudah, jauh lebih dari apa pun yang pernah saya gunakan. Jika Anda pikir ini buruk, coba sesuatu yang lain untuk sementara waktu. Kemudian kembali ke ๐Ÿช: apakah Anda akan kembali ke dunia yang lebih baik, atau Anda akan membawa pengetahuan yang sama dengan Anda sehingga kami dapat menggunakan pengetahuan baru Anda untuk menjadikan ๐Ÿช lebih baik dalam hal-hal ini.


๐Ÿ’ก ๐•ด๐–‰๐–Š๐–†๐–˜ ๐–‹๐–”๐–— ๐–† ๐–€๐–“๐–Ž๐–ˆ๐–”๐–‰๐–Š โธ— ๐•ฌ๐–œ๐–†๐–—๐–Š ๐Ÿช ๐Ÿช ๐•ท๐–†๐–š๐–“๐–‰๐–—๐–ž ๐Ÿ’ก


Minimal, berikut adalah beberapa hal yang tampaknya diperlukan untuk ๐Ÿช untuk โ€œmengaktifkan Unicode secara defaultโ€, seperti yang Anda katakan:

  1. Semua ๐Ÿช kode sumber harus dalam UTF-8 secara default. Anda bisa mendapatkannya dengan use utf8atau export PERL5OPTS=-Mutf8.

  2. DATAPegangan ๐Ÿช haruslah UTF-8. Anda harus melakukan ini per paket, seperti pada binmode(DATA, ":encoding(UTF-8)").

  3. Argumen program untuk ๐Ÿช skrip harus dipahami sebagai UTF-8 secara default. export PERL_UNICODE=A, atau perl -CA, atau export PERL5OPTS=-CA.

  4. Input standar, output, dan stream kesalahan harus default ke UTF-8. export PERL_UNICODE=Suntuk mereka semua, atau I, Odan / atau Ehanya beberapa dari mereka. Ini seperti perl -CS.

  5. Pegangan lain yang dibuka oleh ๐Ÿช harus dianggap UTF-8 kecuali dinyatakan sebaliknya; export PERL_UNICODE=Datau dengan idan ountuk yang khusus ini; export PERL5OPTS=-CDakan bekerja. Itu membuat -CSADuntuk mereka semua.

  6. Tutupi kedua pangkalan ditambah semua aliran yang Anda buka export PERL5OPTS=-Mopen=:utf8,:std. Lihat unik .

  7. Anda tidak ingin melewatkan kesalahan pengodean UTF-8. Coba export PERL5OPTS=-Mwarnings=FATAL,utf8. Dan pastikan aliran input Anda selalu binmoded untuk :encoding(UTF-8), bukan hanya untuk :utf8.

  8. Poin kode antara 128โ€“255 harus dipahami oleh ๐Ÿช sebagai titik kode Unicode yang sesuai, bukan hanya nilai biner yang tidak berdasar. use feature "unicode_strings"atau export PERL5OPTS=-Mfeature=unicode_strings. Itu akan membuat uc("\xDF") eq "SS"dan "\xE9" =~ /\w/. Sederhana export PERL5OPTS=-Mv5.12atau lebih baik juga akan mendapatkannya.

  9. Karakter Unicode yang dinamai secara default tidak diaktifkan, jadi tambahkan export PERL5OPTS=-Mcharnames=:full,:short,latin,greekatau semacamnya. Lihat uninames dan tcgrep .

  10. Anda hampir selalu membutuhkan akses ke berbagai fungsi dari modul standarUnicode::Normalize berbagai jenis dekomposisi. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD, dan kemudian selalu jalankan barang masuk melalui NFD dan barang keluar dari NFC. Tidak ada I / O lapisan untuk ini belum bahwa aku sadar, tapi lihat NFC , NFD , nfkd , dan nfkc .

  11. Perbandingan string di ๐Ÿช menggunakan eq, ne, lc, cmp, sort, & c & cc selalu salah. Jadi, alih-alih @a = sort @b, Anda perlu @a = Unicode::Collate->new->sort(@b). Mungkin juga tambahkan itu ke export PERL5OPTS=-MUnicode::Collate. Anda bisa men-cache kunci untuk perbandingan biner.

  12. ๐Ÿช built-in suka printfdan writemelakukan hal yang salah dengan data Unicode. Anda perlu menggunakan yang Unicode::GCStringmodul untuk mantan, dan keduanya itu dan juga para Unicode::LineBreakmodul juga untuk yang terakhir. Lihat uwc dan unifmt .

  13. Jika Anda ingin mereka dihitung sebagai bilangan bulat, maka Anda akan harus menjalankan Anda \d+menangkap melalui satu Unicode::UCD::numfungsi karena ๐Ÿช built-in atoi (3) saat ini tidak cukup pintar.

  14. Anda akan memiliki masalah filesystem di sistem file ๐Ÿ‘ฝ. Beberapa sistem file secara diam-diam menegakkan konversi ke NFC; yang lain secara diam-diam menegakkan konversi ke NFD. Dan yang lain masih melakukan hal lain. Beberapa bahkan mengabaikan masalah itu sama sekali, yang mengarah ke masalah yang lebih besar. Jadi, Anda harus melakukan penanganan NFC / NFD Anda sendiri untuk tetap waras.

  15. Semua ๐Ÿช kode Anda melibatkan a-zatau A-Zdan semacamnya harus diubah , termasuk m//, s///, dan tr///. Itu harus menonjol sebagai bendera merah berteriak bahwa kode Anda rusak. Tetapi tidak jelas bagaimana itu harus berubah. Mendapatkan properti yang tepat, dan memahami lipatannya, lebih sulit dari yang Anda kira. Saya menggunakan unichars dan uniprops setiap hari.

  16. Kode yang digunakan \p{Lu}hampir sama salahnya dengan kode yang digunakan [A-Za-z]. Anda perlu menggunakannya \p{Upper}sebagai gantinya, dan tahu alasannya. Ya, \p{Lowercase}dan \p{Lower}berbeda dari \p{Ll}dan \p{Lowercase_Letter}.

  17. Kode yang digunakan [a-zA-Z]bahkan lebih buruk. Dan itu tidak bisa menggunakan \pLatau \p{Letter}; itu perlu digunakan \p{Alphabetic}. Tidak semua alfabet adalah huruf, Anda tahu!

  18. Jika Anda mencari variabel ๐Ÿช dengan /[\$\@\%]\w+/, maka Anda memiliki masalah. Anda perlu mencari /[\$\@\%]\p{IDS}\p{IDC}*/, dan bahkan itu tidak memikirkan variabel tanda baca atau variabel paket.

  19. Jika Anda memeriksa spasi putih, maka Anda harus memilih antara \hdan \v, tergantung. Dan Anda tidak boleh menggunakan \s, karena TIDAK BERARTI [\h\v] , bertentangan dengan kepercayaan populer.

  20. Jika Anda menggunakan \nuntuk batas garis, atau bahkan \r\n, maka Anda melakukannya dengan salah. Anda harus menggunakan \R, yang tidak sama!

  21. Jika Anda tidak tahu kapan dan apakah akan memanggil Unicode :: Stringprep , maka Anda sebaiknya belajar.

  22. Perbandingan case-insensitive perlu memeriksa apakah dua hal adalah huruf yang sama tidak peduli diakritik dan sejenisnya. Cara termudah untuk melakukannya adalah dengan modul Unicode :: Collate standar . Unicode::Collate->new(level => 1)->cmp($a, $b). Ada juga eqmetode dan semacamnya, dan Anda mungkin harus belajar tentang matchdan substrmetode juga. Ini memiliki keunggulan berbeda dibandingkan ๐Ÿช built-in.

  23. Kadang-kadang itu masih belum cukup, dan Anda membutuhkan modul Unicode :: Collate :: Locale , seperti pada Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)gantinya. Anggap itu Unicode::Collate::->new(level => 1)->eq("d", "รฐ")benar, tetapi Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " รฐ")salah. Demikian pula, "ae" dan "รฆ" adalah eqjika Anda tidak menggunakan bahasa lokal, atau jika Anda menggunakan bahasa Inggris, tetapi mereka berbeda di lokal Islandia. Sekarang apa? Ini sulit, saya katakan. Anda dapat bermain dengan ucsort untuk menguji beberapa hal ini.

  24. Pertimbangkan cara mencocokkan pola CVCV (konsonan, vokal, konsonan, vokal) dalam string โ€œ niรฑo โ€. Bentuk NFD-nya - yang sudah Anda ingat lebih baik untuk diingat - menjadi "nin \ x {303} o". Sekarang apa yang akan kamu lakukan? Bahkan berpura-pura bahwa vokal [aeiou](yang salah, ngomong-ngomong), Anda tidak akan dapat melakukan sesuatu seperti (?=[aeiou])\X)itu, karena bahkan di NFD titik kode seperti 'รธ' tidak terurai ! Namun, itu akan menguji sama dengan 'o' menggunakan perbandingan UCA saya baru saja menunjukkan kepada Anda. Anda tidak dapat mengandalkan NFD, Anda harus bergantung pada UCA.


๐Ÿ’ฉ ๐”ธ ๐•ค ๐•ค ๐•ฆ ๐•ž ๐•– ๐”น ๐”น ๐•ฃ ๐•œ ๐•œ ๐•– ๐•Ÿ ๐•Ÿ ๐•– ๐•– ๐•ค ๐•ค ๐Ÿ’ฉ


Dan itu belum semuanya. Ada jutaan asumsi rusak yang dibuat orang tentang Unicode. Sampai mereka memahami hal-hal ini, kode ๐Ÿช mereka akan rusak.

  1. Kode yang menganggapnya dapat membuka file teks tanpa menentukan pengkodean rusak.

  2. Kode yang mengasumsikan penyandian default adalah semacam penyandian platform asli rusak.

  3. Kode yang mengasumsikan bahwa halaman web dalam bahasa Jepang atau Cina mengambil lebih sedikit ruang di UTF-16 daripada di UTF-8 salah.

  4. Kode yang mengasumsikan Perl menggunakan UTF โ€‘ 8 secara internal salah.

  5. Kode yang mengasumsikan bahwa kesalahan pengkodean akan selalu menimbulkan pengecualian adalah salah.

  6. Kode yang mengasumsikan poin kode Perl terbatas pada 0x10_FFFF salah.

  7. Kode yang mengasumsikan Anda dapat mengatur $/sesuatu yang akan berfungsi dengan pemisah garis yang valid adalah salah.

  8. Kode yang mengasumsikan kesetaraan pulang pergi pada lipatan, seperti lc(uc($s)) eq $satau uc(lc($s)) eq $s, benar-benar rusak dan salah. Pertimbangkan itu uc("ฯƒ")dan uc("ฯ‚") keduanya "ฮฃ", tetapi lc("ฮฃ")tidak mungkin mengembalikan keduanya.

  9. Kode yang mengasumsikan setiap titik kode huruf kecil memiliki satu huruf besar yang berbeda, atau sebaliknya, rusak. Misalnya, "ยช"adalah huruf kecil tanpa huruf besar; sedangkan keduanya "แตƒ"dan "แดฌ"huruf, tetapi mereka bukan huruf kecil; Namun, keduanya merupakan titik kode huruf kecil tanpa versi huruf besar yang sesuai. Mengerti? Mereka tidak \p{Lowercase_Letter} , meskipun keduanya \p{Letter}dan \p{Lowercase}.

  10. Kode yang menganggap mengubah case tidak mengubah panjang string yang rusak.

  11. Kode itu menganggap hanya ada dua kasus yang rusak. Ada juga titlecase.

  12. Kode yang mengasumsikan hanya huruf yang memiliki huruf rusak. Di luar hanya huruf, ternyata angka, simbol, dan bahkan tanda memiliki huruf. Bahkan, mengubah case bahkan dapat membuat sesuatu mengubah kategori umum utamanya, seperti \p{Mark}berubah menjadi a \p{Letter}. Itu juga dapat membuatnya beralih dari satu skrip ke skrip lain.

  13. Kode yang mengasumsikan bahwa case tidak pernah bergantung pada lokal, rusak.

  14. Kode yang mengasumsikan Unicode memberikan ara tentang lokal POSIX rusak.

  15. Kode yang mengasumsikan Anda dapat menghapus diakritik untuk mendapatkan pangkalan huruf ASCII adalah jahat, masih, rusak, rusak otak, salah, dan pembenaran untuk hukuman mati.

  16. Kode yang mengasumsikan bahwa diakritik \p{Diacritic}dan tanda \p{Mark}adalah hal yang sama rusak.

  17. Kode yang mengasumsikan \p{GC=Dash_Punctuation}mencakup sebanyak \p{Dash}yang rusak.

  18. Kode yang mengasumsikan tanda hubung, tanda hubung, dan minus adalah hal yang sama satu sama lain, atau hanya ada satu, yang rusak dan salah.

  19. Kode yang mengasumsikan setiap titik kode membutuhkan tidak lebih dari satu kolom cetak rusak.

  20. Kode yang mengasumsikan bahwa semua \p{Mark}karakter yang mengambil nol kolom cetak rusak.

  21. Kode yang mengasumsikan bahwa karakter yang mirip sama - sama rusak.

  22. Kode yang mengasumsikan bahwa karakter yang tidak mirip tidak rusak.

  23. Kode yang mengasumsikan ada batas jumlah poin kode dalam satu baris yang hanya \Xcocok satu orang saja salah.

  24. Kode yang mengasumsikan \Xtidak akan pernah bisa dimulai dengan \p{Mark}karakter salah.

  25. Kode yang mengasumsikan bahwa \Xtidak dapat menampung dua \p{Mark}karakter bukan salah.

  26. Kode yang menganggap bahwa itu tidak dapat digunakan "\x{FFFF}"adalah salah.

  27. Kode yang mengasumsikan titik kode non-BMP yang membutuhkan dua unit kode UTF-16 (pengganti) akan menyandikan dua karakter UTF-8 yang terpisah, satu per unit kode, salah. Itu tidak: itu dikodekan ke titik kode tunggal.

  28. Kode yang mentranskode dari UTF โ€ 16 atau UTF โ€ 32 dengan memimpin BOM ke UTF โ€ 8 rusak jika menempatkan BOM pada awal hasil UTF-8. Ini sangat bodoh, insinyur harus menghilangkan kelopak mata mereka.

  29. Kode yang mengasumsikan CESU-8 adalah pengkodean UTF yang valid salah. Demikian juga, kode yang berpikir encoding U + 0000 seperti "\xC0\x80"UTF-8 rusak dan salah. Orang-orang ini juga berhak mendapatkan perawatan kelopak mata.

  30. Kode yang mengasumsikan karakter seperti >selalu menunjuk ke kanan dan <selalu menunjuk ke kiri salah - karena mereka sebenarnya tidak.

  31. Kode yang mengasumsikan jika Anda pertama-tama menampilkan karakter Xdan kemudian karakter Y, bahwa mereka akan ditampilkan sebagai XYsalah. Terkadang tidak.

  32. Kode yang mengasumsikan bahwa ASCII cukup baik untuk menulis bahasa Inggris dengan benar adalah bodoh, picik, buta huruf, rusak, jahat, dan salah. Mati dengan kepala mereka! Jika itu tampak terlalu ekstrem, kita bisa kompromi: untuk selanjutnya mereka dapat mengetik hanya dengan jempol kaki dari satu kaki. (Sisanya akan dilakban.)

  33. Kode yang mengasumsikan bahwa semua \p{Math}titik kode adalah karakter yang terlihat salah.

  34. Kode yang menganggap \whanya berisi huruf, angka, dan garis bawah adalah salah.

  35. Kode yang mengasumsikan bahwa ^dan ~tanda baca salah.

  36. Kode yang mengasumsikan รผmemiliki umlaut salah.

  37. Kode yang meyakini hal-hal seperti โ‚จmengandung huruf apa pun di dalamnya adalah salah.

  38. Kode yang percaya \p{InLatin}sama dengan \p{Latin}rusak berat.

  39. Kode yang percaya bahwa \p{InLatin}hampir selalu berguna hampir pasti salah.

  40. Kode yang meyakini bahwa diberikan $FIRST_LETTERsebagai huruf pertama dalam beberapa alfabet dan $LAST_LETTERsebagai huruf terakhir dalam alfabet yang sama, yang [${FIRST_LETTER}-${LAST_LETTER}]memiliki makna apa pun hampir selalu lengkap rusak dan salah dan tidak berarti.

  41. Kode yang meyakini nama seseorang hanya dapat memuat karakter tertentu adalah bodoh, menyinggung, dan salah.

  42. Kode yang mencoba mereduksi Unicode menjadi ASCII tidak hanya salah, pelakunya tidak boleh diijinkan bekerja dalam pemrograman lagi. Titik. Saya bahkan tidak yakin mereka bahkan harus diizinkan untuk melihat lagi, karena sejauh ini tidak ada gunanya bagi mereka.

  43. Kode yang percaya ada beberapa cara untuk berpura-pura penyandian file teks tidak ada yang rusak dan berbahaya. Mungkin juga menyodok mata lainnya.

  44. Kode yang mengubah karakter yang tidak dikenal menjadi ?rusak, bodoh, braindead, dan berjalan bertentangan dengan rekomendasi standar, yang mengatakan JANGAN MELAKUKANNYA! RTFM mengapa tidak.

  45. Kode yang percaya itu dapat dengan andal menebak penyandian dari textfile tidak bertanda bersalah atas kesalahan fatal dari keangkuhan dan naif yang hanya bisa diperbaiki oleh petir dari Zeus.

  46. Kode yang meyakini Anda dapat menggunakan printflebar ๐Ÿช untuk membalut dan membenarkan data Unicode rusak dan salah.

  47. Kode yang percaya begitu Anda berhasil membuat file dengan nama yang diberikan, bahwa ketika Anda menjalankan lsatau readdirpada direktori terlampir, Anda akan benar-benar menemukan file dengan nama yang Anda buat itu bermasalah, rusak, dan salah. Berhentilah terkejut dengan ini!

  48. Kode yang meyakini UTF-16 adalah pengodean dengan lebar tetap adalah bodoh, rusak, dan salah. Cabut lisensi pemrograman mereka.

  49. Kode yang memperlakukan titik kode dari satu bidang dengan cara yang berbeda dengan yang dari bidang lain adalah ipso facto rusak dan salah. Kembali ke sekolah.

  50. Kode yang meyakini bahwa hal-hal seperti /s/ihanya dapat cocok "S"atau "s"rusak dan salah. Anda akan terkejut.

  51. Kode yang digunakan \PM\pM*untuk menemukan cluster grapheme alih-alih menggunakan \Xrusak dan salah.

  52. Orang-orang yang ingin kembali ke dunia ASCII harus didorong sepenuh hati untuk melakukannya, dan untuk menghormati peningkatan mulia mereka, mereka harus diberikan secara gratis dengan mesin tik manual pra-listrik untuk semua kebutuhan entri data mereka. Pesan yang dikirim kepada mereka harus dikirim melalui telegraf berukuran 40 karakter per baris dan dikirimkan langsung oleh kurir. BERHENTI.


๐Ÿ˜ฑ ๐•พ ๐–€ ๐•ธ ๐•ธ ๐•ฌ ๐•ฝ ๐–„ ๐Ÿ˜ฑ


Saya tidak tahu berapa banyak โ€œUnicode default di ๐Ÿชโ€ yang bisa Anda dapatkan dari apa yang saya tulis. Yah, ya saya lakukan: Anda harus menggunakan Unicode::CollatedanUnicode::LineBreak juga. Dan mungkin lebih.

Seperti yang Anda lihat, ada terlalu banyak Unicode hal yang Anda benar-benar tidak harus khawatir tentang untuk itu pernah ada hal seperti itu sebagai โ€œdefault untuk Unicodeโ€.

Apa yang akan Anda temukan, sama seperti yang kita lakukan pada ๐Ÿช 5.8, bahwa tidak mungkin untuk memaksakan semua hal ini pada kode yang belum dirancang sejak awal untuk menjelaskannya. Keegoisan bermaksud baik Anda baru saja menghancurkan seluruh dunia.

Dan bahkan setelah Anda melakukannya, masih ada masalah kritis yang membutuhkan banyak pemikiran untuk menjadi benar. Tidak ada sakelar yang bisa Anda balikkan. Tidak ada apa-apa selain otak, dan maksud saya otak nyata , akan cukup di sini. Ada banyak hal yang harus Anda pelajari. Modulo mundur ke mesin tik manual, Anda tidak bisa berharap untuk menyelinap di ketidaktahuan. Ini adalah abad ke-21, dan Anda tidak bisa berharap Unicode pergi karena ketidaktahuan yang disengaja.

Anda harus mempelajarinya. Titik. Tidak akan pernah semudah itu "semuanya berjalan baik," karena itu akan menjamin bahwa banyak hal tidak berfungsi - yang menggugurkan asumsi bahwa akan pernah ada cara untuk "membuat semuanya berfungsi."

Anda mungkin bisa mendapatkan beberapa default yang masuk akal untuk operasi yang sangat sedikit dan sangat terbatas, tetapi tidak tanpa memikirkan banyak hal lebih banyak daripada yang saya pikir Anda miliki.

Sebagai satu contoh saja, pemesanan kanonik akan menyebabkan beberapa sakit kepala nyata. ๐Ÿ˜ญ "\x{F5}" 'รต' , "o\x{303}" 'รต' , "o\x{303}\x{304}" 'ศญ' , dan "o\x{304}\x{303}" 'ลฬƒ' harus cocok dengan semua 'รต' , tetapi bagaimana kamu bisa melakukan itu? Ini lebih sulit daripada yang terlihat, tetapi ini adalah sesuatu yang perlu Anda pertanggungjawabkan. ๐Ÿ’ฃ

Jika ada satu hal yang saya ketahui tentang Perl, itu adalah apa yang bit Unicode lakukan dan tidak lakukan, dan hal ini saya janjikan kepada Anda: "ฬฒแด›ฬฒสœฬฒแด‡ฬฒส€ฬฒแด‡ฬฒ ฬฒษชฬฒsฬฒ ฬฒษดฬฒแดฬฒ ฬฒษดฬฒษชฬฒแด„ฬฒแดฬฒแด…ฬฒแด‡ฬฒUฬฒษดฬฒษชฬฒแด„ฬฒแดฬฒแด…ฬฒแด‡ฬฒ ฬฒแดฬฒแด€ฬฒษขฬฒษชฬฒแด„ฬฒ ฬฒษดฬฒษชฬฒแด„ฬฒแดฬฒแด…ฬฒแด‡ฬฒ ฬฒส™ฬฒแดœฬฒสŸฬฒสŸฬฒแด‡ฬฒแด›ฬฒ ฬฒ" ๐Ÿ˜ž

Anda tidak bisa hanya mengubah beberapa default dan mendapatkan pelayaran yang lancar. Memang benar bahwa saya menjalankan ๐Ÿช dengan PERL_UNICODEset ke "SA", tapi itu saja, dan bahkan itu sebagian besar untuk hal-hal baris perintah. Untuk pekerjaan nyata, saya melewati semua langkah yang dijelaskan di atas, dan saya melakukannya dengan sangat, ** sangat ** dengan hati-hati.


๐Ÿ˜ˆ ยกฦจdlษ™ษฅ ฦจแด‰ษฅส‡ ษ™doษฅ puษ สปฮปษp ษ™ษ”แด‰u ษ ษ™สŒษษฅ สžษ” สปสžษ”nl pooโ… ๐Ÿ˜ˆ

tchrist
sumber
56
Seperti yang ditunjukkan Sherm Pendley: "Semua!". Jika saya menulis sesuatu yang baru hari ini, UTF-8 seharusnya menjadi cara termudah untuk menyelesaikan sesuatu. Bukan itu. Ketel uap Anda mendukungnya. Tidak semua orang memiliki pengetahuan untuk mengubah begitu banyak gelas ke posisi yang tepat. Maaf, saya mengalami hari yang panjang dan berat, jadi saya akan berkomentar di entri utama besok lebih banyak dengan contoh.
minggu
17
Satu kesimpulan harus jelas dari membaca daftar di atas: Jangan berlipat-lipat. Hanya saja, jangan. Pernah. Mahal secara komputasional dan dengan semantik yang sangat bergantung pada apa pun yang "lokal" berusaha gagal mengidentifikasi.
Tim Bray
72
Apakah saya satu-satunya yang merasa ironis bahwa tulisan yang dibuat oleh tchrist ini sangat berbeda di FF / Chrome / IE / Opera, kadang-kadang sampai pada titik tidak terbaca?
damageboy
15
Sementara saya umumnya suka posting, dan melakukan upvote, satu hal yang mengganggu saya. Ada banyak "kode yang ... rusak". Meskipun saya tidak membantah pernyataan itu, saya pikir akan bagus untuk menunjukkan kehancurannya. Dengan cara ini akan melintasi (bagian jawaban) dari kata kasar, ke pendidikan.
36
@ xenoterracide Tidak, saya tidak menggunakan titik kode yang sengaja bermasalah; itu plot untuk membuat Anda menginstal font Symbola super-mengagumkan George Douros , yang mencakup Unicode 6.0. ๐Ÿ˜ˆ @depesz Tidak ada ruang di sini untuk menjelaskan mengapa setiap assuption yang rusak salah. @leonbloy Banyak dan banyak ini berlaku untuk Unicode secara umum, bukan hanya Perl. Beberapa materi ini mungkin muncul di ๐Ÿช Programming Perl edition edisi ke-4 , yang akan keluar pada bulan Oktober. ๐ŸŽƒ Saya masih punya satu bulan untuk โœ mengerjakannya, dan Unicode แดแด‡ษขแด€ di sana; regex, juga
tchrist
96

Ada dua tahap untuk memproses teks Unicode. Yang pertama adalah "bagaimana saya bisa memasangnya dan mengeluarkannya tanpa kehilangan informasi". Yang kedua adalah "bagaimana saya memperlakukan teks sesuai dengan konvensi bahasa lokal".

Posting tchrist mencakup keduanya, tetapi bagian kedua adalah dari mana 99% teks dalam posnya berasal. Sebagian besar program bahkan tidak menangani I / O dengan benar, jadi penting untuk memahami bahwa sebelum Anda mulai khawatir tentang normalisasi dan penyatuan.

Posting ini bertujuan untuk menyelesaikan masalah pertama itu

Ketika Anda membaca data ke Perl, tidak peduli apa itu pengkodean. Ini mengalokasikan beberapa memori dan menyimpan byte di sana. Jika Anda mengatakanprint $str , itu hanya mengeluarkan byte itu ke terminal Anda, yang mungkin diatur untuk menganggap semua yang ditulis untuk itu adalah UTF-8, dan teks Anda muncul.

Menakjubkan.

Kecuali, tidak. Jika Anda mencoba memperlakukan data sebagai teks, Anda akan melihat bahwa Sesuatu yang Buruk sedang terjadi. Anda tidak perlu melangkah lebih jauh daripada lengthmelihat bahwa apa yang dipikirkan Perl tentang string Anda dan apa yang Anda pikirkan tentang string Anda tidak setuju. Tulis one-liner seperti: perl -E 'while(<>){ chomp; say length }'dan ketikkan ๆ–‡ๅญ—ๅŒ–ใ‘dan Anda dapatkan 12 ... bukan jawaban yang benar, 4.

Itu karena Perl menganggap string Anda bukan teks. Anda harus mengatakan bahwa itu adalah teks sebelum akan memberikan jawaban yang tepat.

Itu cukup mudah; modul Encode memiliki fungsi untuk melakukan itu. Titik masuk umum adalah Encode::decode(atauuse Encode qw(decode) , tentu saja). Fungsi itu mengambil beberapa string dari dunia luar (apa yang kita sebut "oktet", yang suka mengatakan "8-bit byte"), dan mengubahnya menjadi beberapa teks yang Perl akan mengerti. Argumen pertama adalah nama pengkodean karakter, seperti "UTF-8" atau "ASCII" atau "EUC-JP". Argumen kedua adalah string. Nilai kembali adalah skalar Perl yang berisi teks.

(Ada juga Encode::decode_utf8, yang mengasumsikan UTF-8 untuk pengkodean.)

Jika kita menulis ulang one-liner kita:

perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

Kami mengetikkan ๆ–‡ๅญ— ๅŒ– ใ‘ dan mendapatkan "4" sebagai hasilnya. Keberhasilan.

Itu, di sana, adalah solusi untuk 99% masalah Unicode di Perl.

Kuncinya adalah, setiap kali ada teks masuk ke program Anda, Anda harus memecahkan kode itu. Internet tidak dapat mengirim karakter. File tidak dapat menyimpan karakter. Tidak ada karakter di database Anda. Hanya ada oktet, dan Anda tidak bisa memperlakukan oktet sebagai karakter dalam Perl. Anda harus mendekode oktet yang disandikan menjadi karakter Perl dengan modul Encode.

Setengah dari masalah lainnya adalah mengeluarkan data dari program Anda. Itu mudah; Anda hanya mengatakan use Encode qw(encode), tentukan pengkodean data Anda nantinya (UTF-8 ke terminal yang memahami UTF-8, UTF-16 untuk file di Windows, dll.), lalu output hasil encode($encoding, $data)alih-alih hanya menghasilkan $data.

Operasi ini mengubah karakter Perl, yang menjadi tujuan program Anda, menjadi oktet yang dapat digunakan oleh dunia luar. Akan jauh lebih mudah jika kita bisa mengirim karakter melalui Internet atau ke terminal kita, tetapi kita tidak bisa: oktet saja. Jadi kita harus mengonversi karakter menjadi oktet, jika tidak hasilnya tidak akan ditentukan.

Untuk meringkas: encode semua output dan decode semua input.

Sekarang kita akan berbicara tentang tiga masalah yang membuat ini sedikit menantang. Yang pertama adalah perpustakaan. Apakah mereka menangani teks dengan benar? Jawabannya adalah ... mereka mencoba. Jika Anda mengunduh halaman web, LWP akan mengembalikan hasil Anda sebagai teks. Jika Anda memanggil metode yang tepat pada hasilnya, yaitu (dan itu kebetulan decoded_content, bukan content, yang hanya aliran oktet yang didapat dari server.) Driver database dapat bersisik; jika Anda menggunakan DBD :: SQLite hanya dengan Perl, itu akan berhasil, tetapi jika beberapa alat lain telah menempatkan teks disimpan sebagai beberapa penyandian selain UTF-8 dalam database Anda ... well ... itu tidak akan ditangani dengan benar sampai Anda menulis kode untuk menanganinya dengan benar.

Meng-output data biasanya lebih mudah, tetapi jika Anda melihat "karakter luas dicetak", maka Anda tahu Anda mengacaukan penyandian di suatu tempat. Peringatan itu berarti "hei, Anda mencoba membocorkan karakter Perl ke dunia luar dan itu tidak masuk akal". Program Anda tampaknya berfungsi (karena ujung lainnya biasanya menangani karakter Perl mentah dengan benar), tetapi sangat rusak dan dapat berhenti berfungsi kapan saja. Perbaiki dengan eksplisit Encode::encode!

Masalah kedua adalah kode sumber UTF-8 yang dikodekan. Kecuali Anda mengatakan use utf8di bagian atas setiap file, Perl tidak akan menganggap bahwa kode sumber Anda adalah UTF-8. Ini berarti bahwa setiap kali Anda mengatakan sesuatu seperti my $var = 'ใปใ’', Anda memasukkan sampah ke dalam program Anda yang benar-benar akan menghancurkan segalanya. Anda tidak harus "menggunakan utf8", tetapi jika tidak, Anda tidak boleh menggunakan karakter non-ASCII dalam program Anda.

Masalah ketiga adalah bagaimana Perl menangani Masa Lalu. Dahulu kala, tidak ada yang namanya Unicode, dan Perl berasumsi bahwa semuanya adalah teks Latin-1 atau biner. Jadi ketika data masuk ke program Anda dan Anda mulai memperlakukannya sebagai teks, Perl memperlakukan setiap oktet sebagai karakter Latin-1. Itu sebabnya, ketika kami meminta panjang "ๆ–‡ๅญ— ๅŒ– ใ‘", kami mendapat 12. Perl menganggap bahwa kami beroperasi pada string Latin-1 "รฆรฅรฅรฃ" (yang terdiri dari 12 karakter, beberapa di antaranya non-cetak).

Ini disebut "pemutakhiran implisit", dan itu adalah hal yang sangat masuk akal untuk dilakukan, tetapi bukan itu yang Anda inginkan jika teks Anda bukan Latin-1. Itu sebabnya sangat penting untuk secara eksplisit mendekodekan input: jika Anda tidak melakukannya, Perl akan melakukannya, dan itu mungkin salah.

Orang-orang mengalami masalah di mana setengah data mereka adalah string karakter yang tepat, dan beberapa masih bersifat biner. Perl akan menginterpretasikan bagian yang masih biner seolah-olah itu teks Latin-1 dan kemudian menggabungkannya dengan data karakter yang benar. Ini akan membuatnya terlihat seperti menangani karakter Anda dengan benar merusak program Anda, tetapi pada kenyataannya, Anda belum cukup memperbaikinya.

Berikut ini sebuah contoh: Anda memiliki program yang membaca file teks UTF-8-encoded, Anda menempelkan Unicode PILE OF POOke setiap baris, dan Anda mencetaknya. Anda menulis seperti:

while(<>){
    chomp;
    say "$_ ๐Ÿ’ฉ";
}

Dan kemudian jalankan beberapa data yang disandikan UTF-8, seperti:

perl poo.pl input-data.txt

Ini mencetak data UTF-8 dengan kotoran di akhir setiap baris. Sempurna, program saya berfungsi!

Tapi tidak, Anda hanya melakukan penggabungan biner. Anda membaca oktet dari file, menghapus \nchomp dengan, dan kemudian menempelkan byte dalam representasi PILE OF POOkarakter UTF-8 . Ketika Anda merevisi program Anda untuk memecahkan kode data dari file dan menyandikan output, Anda akan melihat bahwa Anda mendapatkan sampah ("รฐ ยฉ") bukan kotoran. Ini akan membuat Anda percaya bahwa decoding file input adalah hal yang salah untuk dilakukan. Ini bukan.

Masalahnya adalah bahwa kotoran secara implisit ditingkatkan sebagai latin-1. Jika Anda use utf8membuat teks literal alih-alih biner, maka teks itu akan berfungsi lagi!

(Itulah masalah nomor satu yang saya lihat ketika membantu orang dengan Unicode. Mereka melakukan bagian yang benar dan itu merusak program mereka. Itulah yang menyedihkan tentang hasil yang tidak ditentukan: Anda dapat memiliki program kerja untuk waktu yang lama, tetapi ketika Anda mulai memperbaikinya, itu rusak. Jangan khawatir, jika Anda menambahkan pernyataan encode / decode ke program Anda dan itu rusak, itu berarti Anda memiliki lebih banyak pekerjaan yang harus dilakukan. Lain kali, ketika Anda merancang dengan Unicode dalam pikiran dari awal, itu akan menjadi jauh lebih mudah!)

Itu benar-benar semua yang perlu Anda ketahui tentang Perl dan Unicode. Jika Anda memberi tahu Perl apa data Anda, itu memiliki dukungan Unicode terbaik di antara semua bahasa pemrograman populer. Namun, jika Anda menganggapnya secara ajaib akan tahu jenis teks apa yang Anda masukkan, maka Anda akan membuang data Anda tanpa bisa dibatalkan. Hanya karena program Anda bekerja hari ini di terminal UTF-8 Anda tidak berarti itu akan berfungsi besok pada file yang dikodekan UTF-16. Jadi amankan sekarang, dan selamatkan diri Anda dari pusing merusak data pengguna Anda!

Bagian yang mudah dari penanganan Unicode adalah menyandikan keluaran dan mendekode masukan. Bagian yang sulit adalah menemukan semua input dan output Anda, dan menentukan pengkodean mana. Tapi itu sebabnya Anda mendapatkan banyak uang :)

jrockway
sumber
Prinsipnya dijelaskan dengan baik, tetapi pendekatan praktis untuk I / O tidak ada. Secara eksplisit menggunakan Encodemodul itu membosankan dan rentan kesalahan, dan itu membuat membaca kode tentang I / O benar-benar menyakitkan. Lapisan I / O memberikan solusi karena secara transparan disandikan dan didekode, jika diperlukan. opendan binmodememungkinkan untuk spesifikasinya, dan pragma openmenetapkan standarnya, seperti yang direkomendasikan tchrist dalam jawabannya.
Palec
48

Kita semua sepakat bahwa ini adalah masalah yang sulit karena banyak alasan, tetapi justru itulah alasan untuk mencoba membuatnya lebih mudah bagi semua orang.

Ada modul terbaru tentang CPAN, utf8 :: all , yang mencoba untuk "mengaktifkan Unicode. Semuanya".

Seperti yang telah ditunjukkan, Anda tidak dapat secara ajaib membuat seluruh sistem (program luar, permintaan web eksternal, dll.) Menggunakan Unicode juga, tetapi kami dapat bekerja sama untuk membuat alat yang masuk akal yang membuat melakukan masalah umum lebih mudah. Itulah alasan mengapa kami adalah programmer.

Jika utf8 :: semua tidak melakukan sesuatu yang menurut Anda seharusnya, mari kita perbaiki untuk membuatnya lebih baik. Atau mari kita membuat alat tambahan yang bersama-sama dapat memenuhi kebutuhan beragam orang sebaik mungkin.

`

Randy Stauner
sumber
5
Saya melihat banyak ruang untuk perbaikan dalam utf8::allmodul yang dikutip . Itu ditulis sebelum unicode_stringsfitur, yang Fแด› แด€ษดแด… แด€แด› Lแดษดษข Lแด€sแด› memperbaiki regex untuk memilikinya /upada mereka. Saya tidak yakin ini memunculkan pengecualian pada kesalahan penyandian, dan itu adalah sesuatu yang benar-benar harus Anda miliki. Itu tidak dimuat dalam use charnames ":full"pragma, yang belum dimuat secara otomatis. Itu tidak memperingatkan [a-z]dan sebagainya, printflebar string, menggunakan \nbukan \Rdan .bukannya \X, tapi mungkin itu lebih merupakan Perl::Criticmasalah. Jika saya, saya akan menambahkan ๐๐…๐ƒ masuk dan ๐๐…๐‚ keluar.
tchrist
13
@tchrist Pelacak isu utf8 :: all ada di sini. github.com/doherty/utf8-all/issues Mereka akan senang mendengar saran Anda.
Schwern
4
@Schwern: แด‡ษดแดแด›แดœษชแด›s, tetapi merasa bebas untuk mencuri dan mencubit dari hal-hal yang saya tulis di sini. Sejujurnya, saya masih merasa / belajar apa yang bisa dilakukan vs apa yang harus dilakukan, dan di mana. Berikut adalah contoh yang bagus dari offloading menyortir: unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r. Demikian pula, langkah-langkah preprocessing kecil seperti ... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'bisa sangat bagus juga, dan saya tidak ingin membuat keputusan orang lain untuk mereka. Saya masih membangun kotak alat Unicode saya .
tchrist
35

Saya pikir Anda salah paham Unicode dan hubungannya dengan Perl. Tidak peduli ke arah mana Anda menyimpan data, Unicode, ISO-8859-1 , atau banyak hal lainnya, program Anda harus tahu bagaimana menafsirkan byte yang didapat sebagai input (decoding) dan bagaimana merepresentasikan informasi yang ingin dihasilkan (pengkodean) ). Dapatkan interpretasi yang salah dan Anda memutarbalikkan data. Tidak ada pengaturan default ajaib di dalam program Anda yang akan memberitahu hal-hal di luar program Anda bagaimana harus bertindak.

Anda pikir itu sulit, kemungkinan besar, karena Anda terbiasa dengan segala sesuatu yang ASCII. Segala sesuatu yang seharusnya Anda pikirkan hanya diabaikan oleh bahasa pemrograman dan semua hal yang harus berinteraksi dengannya. Jika semuanya tidak menggunakan apa-apa selain UTF-8 dan Anda tidak punya pilihan, maka UTF-8 akan sama mudahnya. Tapi tidak semuanya menggunakan UTF-8. Misalnya, Anda tidak ingin pegangan input Anda berpikir bahwa itu mendapatkan oktet UTF-8 kecuali itu benar-benar, dan Anda tidak ingin output Anda menangani menjadi UTF-8 jika sesuatu yang membaca dari mereka dapat menangani UTF-8 . Perl tidak memiliki cara untuk mengetahui hal-hal itu. Itu sebabnya Anda adalah programmer.

Saya tidak berpikir Unicode di Perl 5 terlalu rumit. Saya pikir itu menakutkan dan orang-orang menghindarinya. Ada perbedaan. Untuk itu, saya telah memasukkan Unicode di Learning Perl, Edisi ke-6 , dan ada banyak hal Unicode di Pemrograman Perl yang Efektif . Anda harus meluangkan waktu untuk belajar dan memahami Unicode dan cara kerjanya. Anda tidak akan dapat menggunakannya secara efektif jika tidak.

brian d foy
sumber
3
Saya pikir Anda ada benarnya: itu menakutkan. Haruskah begitu? Bagi saya adalah berkat Unicode, menggunakannya di Perl5 tidak (saya tidak menganggap apa pun menjadi ASCII, bahasa ibu saya membutuhkan setidaknya iso8859-4). Saya menginstal Rakudo dan semua yang saya coba dengan UTF-8 (di kotak pasir terbatas ini) bekerja di luar kotak. Apakah saya melewatkan sesuatu? Saya menekankan lagi: itu baik untuk memiliki dukungan Unicode yang baik, tetapi pada sebagian besar waktu tidak perlu untuk itu. Untuk menghilangkan rasa takut pada topik, salah satu caranya adalah bahwa setiap orang banyak membaca untuk memahami internal. Lainnya: kami memiliki pragma khusus, sehingga use utf8_everywheremembuat orang senang. Kenapa tidak bertahan lama?
minggu
3
Saya masih berpikir Anda tidak mengerti intinya. Apa yang berhasil? Anda tidak perlu memahami masalah internal. Anda perlu memahami eksternal dan bagaimana Anda ingin menangani string yang memiliki penyandian berbeda dan representasi berbeda dari karakter yang sama. Baca saran Tom lagi. Sebagian besar dari apa yang dia katakan saya yakin Anda akan menemukan Rakudo tidak cocok untuk Anda.
brian d foy
1
@wk: Baca jawaban Randy lagi. Dia sudah memberitahumu apa batasannya.
brian d foy
2
@ Brian d foy: saya pikir batasan itu baik-baik saja, seperti kata tchrist, tidak ada peluru ajaib untuk setiap aspek (saya akui: saya tidak melihat sebagian besar dari mereka sebelum menanyakan pertanyaan ini di sini). Jadi, ketika kita membahas banyak hal dasar dengan sesuatu seperti utf8 :: all, tidak ada kebutuhan bagi semua orang untuk membuat pelat tembok besar sendiri hanya untuk mendapatkan dasar-dasar tentang penanganan utf8 untuk bekerja. Dengan "tanpa rasa takut sama sekali" yang saya maksud: semua orang dapat memulai proyeknya dengan mengetahui bahwa dasar-dasarnya tercakup. Ya, Anda benar, masih ada banyak masalah. Tetapi ketika memulai lebih mudah, kita akan memiliki lebih banyak orang yang terlibat dalam menyelesaikannya. IMHO
minggu
1
@wk - satu-satunya "salah" dengan "utf8: all" atau "uni :: perl hanya satu - mereka tidak di INTI - jadi semua orang harus menginstalnya dari CPAN. Dan jika Anda berpikir bahwa ini bukan masalah besar kesepakatan - pikirkan kembali tolong - ya, lebih mudah menggunakan utf8 dengan modul pembantu. Tanpa itu, perl CORE masih memiliki dukungan unicode - tapi jauh lebih rumit. Dan ini salah
jm666
28

Saat membaca utas ini, saya sering mendapat kesan bahwa orang menggunakan " UTF-8 " sebagai sinonim dengan " Unicode ". Tolong buat perbedaan antara "Kode-Poin" Unicode yang merupakan kerabat yang diperbesar dari kode ASCII dan berbagai "penyandian" Unicode. Dan ada beberapa dari mereka, di mana UTF-8, UTF-16 dan UTF-32 adalah yang saat ini dan beberapa lagi sudah usang.

Tolong, UTF-8 (dan juga semua pengkodean lainnya ) ada dan memiliki arti dalam input atau hanya dalam output. Secara internal, sejak Perl 5.8.1, semua string disimpan sebagai Unicode "Kode-poin". Benar, Anda harus mengaktifkan beberapa fitur yang sebelumnya telah dikagumi.

MeirG
sumber
19
Saya setuju orang terlalu sering membingungkan Uษดษชแด„แดแด…แด‡ dengan UTF-8โงธ16โงธ32, tetapi secara fundamental dan kritis tidak benar bahwa Uษดษชแด„แดแด…แด‡ hanya beberapa karakter yang diperbesar yang diatur relatif ke แด€sแด„ษชษช. Paling-paling, itu tidak lebih dari sekadar 10646 . Uษดษชแด„แดแด…แด‡ mencakup lebih banyak lagi : aturan untuk collation, casefolding, bentuk normalisasi, cluster grapheme, word-& line-breaking, skrip, equivs numerik, lebar, bidirectionality, varian glyph, perilaku kontekstual, lokal, regex, menggabungkan kelas, 100 properti, & lebih banyak lagiโ€ผ
tchrist
15
@tchrist: langkah pertama adalah memasukkan data ke dalam program Anda dan keluar ke dunia luar tanpa merusaknya. maka Anda dapat khawatir tentang collation, lipat kasus, varian mesin terbang, dll langkah bayi.
jrockway
7
Saya setuju, mendapatkan perl untuk tidak membuang input atau output harus menjadi prioritas pertama. Apa yang saya inginkan adalah memiliki modul atau pragma yang dapat mewujudkan percakapan fiktif berikut: "- Dear Perl. Untuk program ini, semua input dan output akan menjadi UTF-8 secara eksklusif. Bisakah Anda tidak membuang data saya? - Jadi hanya UFT-8 yang Anda katakan. Apakah Anda yakin? - Ya. - Sungguh, sangat yakin? - Tentu saja - Dan Anda menerima bahwa saya mungkin berperilaku aneh jika saya melayani data non-UTF-8? - Ya, baik. - Baiklah kalau begitu. "
hlovdal
10

Ada sejumlah kode kuno yang benar-benar mengerikan di luar sana di alam liar, sebagian besar dalam bentuk modul CPAN umum. Saya menemukan saya harus cukup hati-hati mengaktifkan Unicode jika saya menggunakan modul eksternal yang mungkin terpengaruh olehnya, dan saya masih mencoba mengidentifikasi dan memperbaiki beberapa kegagalan terkait Unicode di beberapa skrip Perl yang saya gunakan secara teratur (khususnya, iTiVo gagal buruk pada apa pun yang bukan ASCII 7-bit karena masalah transcoding).

geekosaurus
sumber
Maksud saya menggunakan -Copsi untuk memastikan Perl berada di halaman yang sama dengan saya Unicode-wise, karena saya terus memutuskan untuk menggunakan ISO 8859/1 alih-alih Unicode meskipun saya secara eksplisit mengatur $LANGdan mengaturnya $LC_ALLdengan benar. (Ini sebenarnya mencerminkan bug di pustaka lokal platform.) Apa pun itu, sangat menjengkelkan karena saya tidak dapat menggunakan iTivo pada program dengan aksen di dalamnya karena skrip Perl yang melakukan pekerjaan gagal karena kesalahan konversi.
geekosaur
3
Satu-satunya -Ctanpa opsi adalah buggy dan rawan kesalahan . Anda menghancurkan dunia. Atur PERL5OPTenvariable ke -Cdan Anda akan melihat apa yang saya maksud. Kami mencoba cara ini kembali di v5.8, dan itu adalah bencana. Anda tidak bisa dan tidak boleh memberi tahu program yang tidak mengharapkannya bahwa sekarang mereka berurusan dengan Unicode apakah mereka suka atau tidak. Ada juga masalah keamanan. Paling tidak, apa pun yang dilakukan print while <>akan rusak jika melewati data biner. Demikian juga semua kode basis data. Ini ide yang buruk.
tchrist
1
Saya berbicara secara umum, sebenarnya, tidak secara spesifik -Ctanpa opsi. Doa khusus yang telah saya kerjakan adalah -CSDA. Yang mengatakan, saya terjebak dengan 5.8.x untuk waktu yang lama (halo MacPorts ...), jadi mungkin itu bagian dari itu.
geekosaur
1
Saya menjalankan dengan PERL_UNICODE diatur ke SA. Anda TIDAK BISA mengaturnya ke D.
tchrist
@tchrist: Beberapa Perl varmint telah mem-posting kode yang menunjukkan -CSDA dan PERL_UNICODE = Penggunaan SDA . Silakan gunakan pengaruh Anda di komunitas. Dia harus dihentikan!
Ashley
1

Anda harus mengaktifkan fitur string unicode, dan ini adalah default jika Anda menggunakan v5.14;

Anda seharusnya tidak benar-benar menggunakan pengidentifikasi unicode esp. untuk kode asing via utf8 karena tidak aman di perl5, hanya cperl yang benar. Lihat misalnya http://perl11.org/blog/unicode-identifiers.html

Mengenai utf8 untuk penanganan file / stream Anda: Anda perlu memutuskan sendiri pengkodean data eksternal Anda. Pustaka tidak dapat mengetahui hal itu, dan karena libc bahkan tidak mendukung utf8, data utf8 yang tepat jarang terjadi. Ada lagi wtf8, jendela aberasi utf8 di sekitar.

BTW: Moose tidak benar-benar "Modern Perl", mereka hanya membajak namanya. Moose sempurna Larry Wall-gaya postmodern perl dicampur dengan Bjarne Stroustrup-gaya semuanya berjalan, dengan aberasi eklektik sintaks perl6 yang tepat, misalnya menggunakan string untuk nama variabel, sintaksis bidang yang mengerikan, dan implementasi naif yang sangat tidak matang yang 10x lebih lambat dari pada implementasi yang tepat. cperl dan perl6 adalah perl modern yang benar, di mana bentuk mengikuti fungsi, dan implementasinya dikurangi dan dioptimalkan.

rurban
sumber