Tại sao Perl hiện đại tránh UTF-8 theo mặc định?


557

Tôi tự hỏi tại sao hầu hết các giải pháp hiện đại được xây dựng bằng Perl không bật UTF-8 theo mặc định.

Tôi hiểu rằng có nhiều vấn đề di sản cho các tập lệnh Perl cốt lõi, nơi nó có thể phá vỡ mọi thứ. Tuy nhiên, từ quan điểm của tôi, trong 21 st thế kỷ, các dự án mới lớn (hoặc dự án với một viễn cảnh lớn) nên làm cho phần mềm UTF-8 bằng chứng của họ từ đầu. Tôi vẫn không thấy nó xảy ra. Ví dụ, Moose cho phép nghiêm ngặt và cảnh báo, nhưng không phải là Unicode . Hiện đại :: Perl cũng giảm nồi hơi, nhưng không xử lý UTF-8.

Tại sao? Có một số lý do để tránh UTF-8 trong các dự án Perl hiện đại trong năm 2011?


Nhận xét @tchrist đã quá lâu, vì vậy tôi đang thêm nó vào đây.

Có vẻ như tôi đã không làm cho mình rõ ràng. Hãy để tôi thử thêm một số thứ.

tchrist và tôi thấy tình hình khá giống nhau, nhưng kết luận của chúng tôi hoàn toàn trái ngược nhau. Tôi đồng ý, tình hình với Unicode rất phức tạp, nhưng đây là lý do tại sao chúng tôi (người dùng Perl và người viết mã) cần một số lớp (hoặc pragma) giúp xử lý UTF-8 dễ dàng như hiện nay.

tchrist chỉ vào nhiều khía cạnh để bao quát, tôi sẽ đọc và suy nghĩ về chúng trong nhiều ngày hoặc thậm chí vài tuần. Tuy nhiên, đây không phải là quan điểm của tôi. tchrist cố gắng chứng minh rằng không có một cách duy nhất "để kích hoạt UTF-8". Tôi không có quá nhiều kiến ​​thức để tranh luận với điều đó. Vì vậy, tôi dính vào các ví dụ sống.

Tôi đã chơi xung quanh với Rakudo và UTF-8 đã ở đó khi tôi cần . Tôi không có vấn đề gì, nó chỉ hoạt động. Có thể có một số hạn chế ở đâu đó sâu hơn, nhưng khi bắt đầu, tất cả những gì tôi đã thử nghiệm đã làm việc như tôi mong đợi.

Không phải đó cũng là một mục tiêu trong Perl 5 hiện đại sao? Tôi nhấn mạnh thêm: Tôi không đề xuất UTF-8 làm ký tự mặc định được đặt cho lõi Perl, tôi đề xuất khả năng kích hoạt nó với một cái búng tay cho những người phát triển dự án mới .

Một ví dụ khác, nhưng với một giai điệu tiêu cực hơn. Các khung nên làm cho sự phát triển dễ dàng hơn. Vài năm trước, tôi đã thử các khung web, nhưng chỉ cần ném chúng đi vì "bật UTF-8" rất tối nghĩa. Tôi không tìm thấy cách thức và nơi để hỗ trợ Unicode. Nó tốn rất nhiều thời gian đến nỗi tôi thấy việc đi theo con đường cũ dễ dàng hơn. Bây giờ tôi thấy ở đây có một tiền thưởng để giải quyết vấn đề tương tự với Mason 2: Làm thế nào để làm cho Mason2 UTF-8 sạch sẽ? . Vì vậy, nó là một khung công tác khá mới, nhưng sử dụng nó với UTF-8 cần có kiến ​​thức sâu rộng về các phần bên trong của nó. Nó giống như một dấu hiệu lớn màu đỏ: DỪNG, đừng sử dụng tôi!

Tôi thực sự thích Perl. Nhưng đối phó với Unicode là đau đớn. Tôi vẫn thấy mình chạy vào tường. Một số cách tchrist là đúng và trả lời câu hỏi của tôi: các dự án mới không thu hút UTF-8 vì nó quá phức tạp trong Perl 5.


15
Tôi xin lỗi nhưng tôi đồng ý với @tchrist - UTF-8 cực kỳ khó khăn. Không có khung hoặc công cụ nào chỉ "bật công tắc" và sau đó xử lý chính xác. Đó là điều bạn phải suy nghĩ trực tiếp khi thiết kế ứng dụng của mình - không phải bất kỳ loại khung hoặc ngôn ngữ nào có thể xử lý cho bạn. Nếu rakudo chỉ tình cờ làm việc cho bạn, bạn không đủ phiêu lưu với các trường hợp thử nghiệm của mình - vì nó sẽ lấy một số ví dụ trong câu trả lời của @ tchrist và người bán thịt.
Billy ONeal

12
Chính xác thì bạn đang hy vọng Moose hay Modern :: Perl sẽ làm gì? Kỳ diệu biến dữ liệu ký tự được mã hóa ngẫu nhiên trong các tệp và cơ sở dữ liệu thành dữ liệu hợp lệ một lần nữa?
jrockway

13
Điều đó nghĩa là gì? Moose không có gì để làm với thao tác văn bản. Tại sao nó nên biết về mã hóa ký tự, ít hơn nhiều để chọn một mặc định cho bạn? (Dù sao đi nữa, lý do tại sao các pragma mà bạn liệt kê không chạm vào mã hóa là vì quy ước dành cho các pragma Perl ảnh hưởng đến hành vi từ vựng . Đây không phải là PHP hay Ruby ở đây.)
jrockway

8
(Ngoài ra ... "hầu hết các ứng dụng Perl hiện đại" đều bị hỏng trên UTF-8? Tôi chắc chắn chưa bao giờ viết một ứng dụng nào, Perl hay nói cách khác, đó không phải là Unicode-sạch.)
jrockway

11
Nb. tchrist (Tom Christiansen) đã đăng [ training.perl.com/OSCON2011/index.html Tài liệu của Tom Christiansen cho OSCON 2011] về Unicode. Bài viết có tiêu đề "Bắn súng hỗ trợ Unicode: Tốt, xấu, và (hầu hết) xấu xí" nói về hỗ trợ Unicode trong các ngôn ngữ lập trình khác nhau. Chỉ Google Go và Perl5 mới hỗ trợ Unicode đầy đủ, chỉ có Google Go dựng sẵn (không đề cập đến Perl6).
Jakub Narębski

Câu trả lời:


1146

𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚

  1. Đặt khả năng của bạn PERL_UNICODEthành AS. Điều này làm cho tất cả các tập lệnh Perl giải mã @ARGVthành các chuỗi UTF ‑ 8 và đặt mã hóa của cả ba chuỗi stdin, stdout và stderr thành UTF ‑ 8. Cả hai đều là hiệu ứng toàn cầu, không phải từ vựng.

  2. Ở đầu tệp nguồn của bạn (chương trình, mô-đun, thư viện, dohickey), khẳng định rõ ràng rằng bạn đang chạy perl phiên bản 5.12 hoặc tốt hơn thông qua:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
  3. Kích hoạt cảnh báo, vì tuyên bố trước đó chỉ cho phép các giới hạn và tính năng, không phải cảnh báo. Tôi cũng đề nghị thúc đẩy cảnh báo Unicode vào các trường hợp ngoại lệ, vì vậy hãy sử dụng cả hai dòng này, không chỉ một trong số chúng. Lưu ý tuy nhiên đó dưới v5.14, các utf8lớp cảnh báo bao gồm ba subwarnings khác mà tất cả có thể được kích hoạt riêng biệt: nonchar, surrogate, và non_unicode. Những bạn có thể muốn kiểm soát tốt hơn.

    use warnings;
    use warnings qw( FATAL utf8 );
  4. Khai báo rằng đơn vị nguồn này được mã hóa dưới dạng UTF ‑ 8. Mặc dù ngày xưa, pragma này đã làm những việc khác, nhưng bây giờ nó chỉ phục vụ mục đích duy nhất này và không có mục đích nào khác:

    use utf8;
  5. Tuyên bố rằng bất cứ điều gì mở một tập tin trong phạm vi từ vựng này nhưng không phải ở nơi nào khác là giả định rằng luồng đó được mã hóa trong UTF ‑ 8 trừ khi bạn nói khác. Bằng cách đó, bạn không ảnh hưởng đến mã của mô-đun khác hoặc chương trình khác.

    use open qw( :encoding(UTF-8) :std );
  6. Cho phép các ký tự được đặt tên qua \N{CHARNAME}.

    use charnames qw( :full :short );
  7. Nếu bạn có một DATAtay cầm, bạn phải đặt mã hóa rõ ràng. Nếu bạn muốn đây là UTF ‑ 8, hãy nói:

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

Tất nhiên không có kết thúc của những vấn đề khác mà cuối cùng bạn có thể thấy mình lo lắng, nhưng những điều này sẽ đủ để ước tính mục tiêu nhà nước để làm cho mọi thứ chỉ hoạt động với UTF, 8 8, mặc dù có ý nghĩa hơi yếu về các điều khoản đó.

Một pragma khác, mặc dù nó không liên quan đến Unicode, là:

      use autodie;

Nó được khuyến khích mạnh mẽ.

🐪🐫🐪 🌞 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐁


🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 🐪 🎁


Bản thân nồi hơi của tôi những ngày này có xu hướng trông như thế này:

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__

𝕹 𝖔 𝖆 𝖌 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅


Nói rằng, Perl Perl nên [ bằng cách nào đó! ] bật Unicode theo mặc định, không thậm chí bắt đầu nghĩ về việc đi xung quanh để nói đủ để thậm chí hữu ích một chút trong một số trường hợp hiếm gặp và bị cô lập. Unicode không chỉ là một tiết mục nhân vật lớn hơn; đó cũng là cách những nhân vật đó tương tác với nhau theo nhiều cách.

Ngay cả những biện pháp tối thiểu có đầu óc đơn giản mà (một số) mọi người dường như nghĩ rằng họ muốn được bảo đảm sẽ phá vỡ hàng triệu dòng mã một cách thảm hại, mã không có cơ hội nâng cấp cải tiến thành hiện đại Brave New World mới lạ của bạn .

Đó là cách cách phức tạp hơn mọi người giả vờ. Tôi đã nghĩ về điều này rất nhiều, rất nhiều trong vài năm qua. Tôi rất thích được chỉ ra rằng tôi sai. Nhưng tôi không nghĩ rằng tôi là. Unicode về cơ bản phức tạp hơn mô hình mà bạn muốn áp đặt cho nó, và có một sự phức tạp ở đây là bạn không bao giờ có thể quét dưới thảm. Nếu bạn thử, bạn sẽ phá vỡ mã của riêng bạn hoặc của người khác. Tại một số điểm, bạn chỉ cần chia nhỏ và tìm hiểu về Unicode. Bạn không thể giả vờ nó là một cái gì đó không phải là nó.

Out đi theo cách của nó để làm cho Unicode dễ dàng, nhiều hơn bất cứ thứ gì tôi từng sử dụng. Nếu bạn nghĩ rằng điều này là xấu, hãy thử một cái gì đó khác trong một thời gian. Sau đó quay trở lại: hoặc bạn sẽ trở lại một thế giới tốt hơn, hoặc nếu không bạn sẽ mang kiến ​​thức tương tự với bạn để chúng tôi có thể sử dụng kiến ​​thức mới của bạn để cải thiện những điều này.


𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙 💡


Ở mức tối thiểu, đây là một số điều có vẻ như được yêu cầu đối với 🐪 để bật tính năng Unicode theo mặc định, khi bạn đặt nó:

  1. Theo mặc định, tất cả mã nguồn phải ở dạng UTF-8. Bạn có thể có được điều đó với use utf8hoặc export PERL5OPTS=-Mutf8.

  2. Tay DATAcầm phải là UTF-8. Bạn sẽ phải làm điều này trên cơ sở mỗi gói, như trong binmode(DATA, ":encoding(UTF-8)").

  3. Các đối số chương trình cho 🐪 script nên được hiểu là UTF-8 theo mặc định. export PERL_UNICODE=A, hoặc perl -CA, hoặc export PERL5OPTS=-CA.

  4. Các luồng đầu vào, đầu ra và lỗi tiêu chuẩn nên mặc định là UTF-8. export PERL_UNICODE=Scho tất cả trong số họ, hoặc I, Ovà / hoặc Echo chỉ là một số trong số họ. Đây là như thế perl -CS.

  5. Bất kỳ tay cầm nào khác được mở bởi nên được coi là UTF-8 trừ khi được khai báo khác; export PERL_UNICODE=Dhoặc với iocho những người cụ thể trong số này; export PERL5OPTS=-CDsẽ làm việc Điều đó làm -CSADcho tất cả chúng.

  6. Bao gồm cả hai cơ sở cộng với tất cả các luồng bạn mở với export PERL5OPTS=-Mopen=:utf8,:std. Xem duy nhất .

  7. Bạn không muốn bỏ lỡ lỗi mã hóa UTF-8. Hãy thử export PERL5OPTS=-Mwarnings=FATAL,utf8. Và đảm bảo luồng đầu vào của bạn luôn luôn binmoded :encoding(UTF-8), không chỉ đến :utf8.

  8. Các điểm mã giữa 128 Vang255 nên được hiểu bởi 🐪 là các điểm mã Unicode tương ứng, không chỉ là các giá trị nhị phân chưa được chứng minh. use feature "unicode_strings"hoặc export PERL5OPTS=-Mfeature=unicode_strings. Điều đó sẽ làm uc("\xDF") eq "SS""\xE9" =~ /\w/. Một đơn giản export PERL5OPTS=-Mv5.12hoặc tốt hơn cũng sẽ có được điều đó.

  9. Các ký tự Unicode được đặt tên không được bật theo mặc định, vì vậy hãy thêm export PERL5OPTS=-Mcharnames=:full,:short,latin,greekhoặc một số như vậy. Xem uninamestcgrep .

  10. Bạn hầu như luôn cần truy cập vào các chức năng từ mô-đun tiêu chuẩnUnicode::Normalize các loại phân tách khác nhau. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKDvà sau đó luôn chạy nội dung đến thông qua NFD và nội dung gửi đi từ NFC. Vẫn chưa có lớp I / O cho những điều này mà tôi biết, nhưng hãy xem nfc , nfd , nfkdnfkc .

  11. So sánh chuỗi trong 🐪 sử dụng eq, ne, lc, cmp, sort, & c & cc luôn sai. Vì vậy, thay vì @a = sort @b, bạn cần @a = Unicode::Collate->new->sort(@b). Cũng có thể thêm nó vào của bạn export PERL5OPTS=-MUnicode::Collate. Bạn có thể lưu trữ khóa để so sánh nhị phân.

  12. Tích hợp thích printfwritelàm sai với dữ liệu Unicode. Bạn cần phải sử dụng các Unicode::GCStringmô-đun cho các cựu, và cả hai đó và cũng Unicode::LineBreakmô-đun cũng cho sau này. Xem uwcunifmt .

  13. Nếu bạn muốn họ được tính là số nguyên, sau đó bạn sẽ phải chạy bạn \d+chụp thông qua các Unicode::UCD::numchức năng vì 🐪 được xây dựng-in atoi (3) không phải là hiện đủ thông minh.

  14. Bạn sẽ gặp vấn đề về hệ thống tập tin trên hệ thống tập tin. Một số hệ thống tập tin âm thầm thực thi chuyển đổi sang NFC; những người khác âm thầm thực thi một chuyển đổi sang NFD. Và những người khác vẫn làm một cái gì đó khác. Một số thậm chí bỏ qua vấn đề hoàn toàn, dẫn đến những vấn đề thậm chí còn lớn hơn. Vì vậy, bạn phải tự xử lý NFC / NFD để giữ lành mạnh.

  15. Tất cả 🐪 mã của bạn liên quan đến a-zhoặc A-Zvà như vậy phải được thay đổi , bao gồm m//, s///tr///. Nó nên nổi bật như một lá cờ đỏ đang la hét rằng mã của bạn bị hỏng. Nhưng không rõ nó phải thay đổi như thế nào. Có được các thuộc tính phù hợp và hiểu được các casefold của chúng, khó hơn bạn nghĩ. Tôi sử dụng unicharsuniprops mỗi ngày.

  16. Mã sử ​​dụng \p{Lu}gần như sai như mã sử dụng [A-Za-z]. Bạn cần sử dụng \p{Upper}thay thế, và biết lý do tại sao. Có, \p{Lowercase}\p{Lower}khác với \p{Ll}\p{Lowercase_Letter}.

  17. Mã sử ​​dụng [a-zA-Z]thậm chí còn tồi tệ hơn. Và nó không thể sử dụng \pLhoặc \p{Letter}; nó cần phải sử dụng \p{Alphabetic}. Không phải tất cả các bảng chữ cái là chữ cái, bạn biết!

  18. Nếu bạn đang tìm kiếm 🐪 biến với /[\$\@\%]\w+/, thì bạn có một vấn đề. Bạn cần tìm kiếm /[\$\@\%]\p{IDS}\p{IDC}*/, và thậm chí điều đó không nghĩ về các biến chấm câu hoặc biến gói.

  19. Nếu bạn đang kiểm tra khoảng trắng, thì bạn nên chọn giữa \h\v, tùy thuộc. Và bạn không bao giờ nên sử dụng \s, vì nó KHÔNG Ý NGH [\h\v] , A, trái với niềm tin phổ biến.

  20. Nếu bạn đang sử dụng \ncho một ranh giới dòng, hoặc thậm chí \r\n, thì bạn đang làm sai. Bạn phải sử dụng \R, không giống nhau!

  21. Nếu bạn không biết khi nào và có nên gọi Unicode :: Stringprep hay không , thì bạn đã học tốt hơn.

  22. So sánh không phân biệt chữ hoa chữ thường cần kiểm tra xem hai thứ có phải là cùng một chữ cái hay không, bất kể dấu phụ của chúng là gì. Cách dễ nhất để làm điều đó là với mô-đun Unicode :: Collate tiêu chuẩn . Unicode::Collate->new(level => 1)->cmp($a, $b). Ngoài ra còn có eqcác phương thức và như vậy, và có lẽ bạn cũng nên tìm hiểu về matchsubstrcác phương thức. Đây là những lợi thế khác biệt so với 🐪 tích hợp.

  23. Đôi khi điều đó vẫn chưa đủ và thay vào đó bạn cần mô-đun Unicode :: Collate :: Locale , như Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)thay vào đó. Coi đó Unicode::Collate::->new(level => 1)->eq("d", "ð")là đúng, nhưng Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")là sai Tương tự, "ae" và "" là eqnếu bạn không sử dụng ngôn ngữ địa phương hoặc nếu bạn sử dụng tiếng Anh, nhưng chúng khác nhau ở địa phương Iceland. Giờ thì sao? Thật khó khăn, tôi nói với bạn. Bạn có thể chơi với ucsort để kiểm tra một số thứ này.

  24. Xem xét làm thế nào để khớp với mẫu CVCV (phụ âm, nguyên âm, phụ âm, nguyên âm) trong chuỗi Cách niño Hồi . Hình thức NFD của nó - thứ mà bạn đã thấy rõ hơn là đã nhớ đặt nó vào - trở thành nin nin \ x {303} o. Bây giờ những gì thì bạn sẽ làm gì? Ngay cả khi giả vờ rằng một nguyên âm là [aeiou](sai, nhân tiện), bạn sẽ không thể làm điều gì đó giống như vậy (?=[aeiou])\X), bởi vì ngay cả trong NFD, một điểm mã như 'ø' cũng không bị phân hủy ! Tuy nhiên, nó sẽ kiểm tra bằng 'o' bằng cách sử dụng so sánh UCA mà tôi vừa cho bạn xem. Bạn không thể dựa vào NFD, bạn phải dựa vào UCA.


𝔸 𝕤 𝕤 𝕦 𝕞 𝕖 𝔹 𝕣 𝕠 𝕜 𝕖 𝕟 𝕟 𝕖 𝕤 𝕤 💩


Và đó không phải là tất cả. Có một triệu giả định bị phá vỡ mà mọi người đưa ra về Unicode. Cho đến khi họ hiểu những điều này, mã their của họ sẽ bị phá vỡ.

  1. Mã giả định rằng nó có thể mở tệp văn bản mà không chỉ định mã hóa bị hỏng.

  2. Mã giả định mã hóa mặc định là một số loại mã hóa nền tảng gốc bị hỏng.

  3. Mã giả định rằng các trang web bằng tiếng Nhật hoặc tiếng Trung chiếm ít không gian hơn trong UTF ‑ 16 so với UTF 8 là sai.

  4. Mã giả định Perl sử dụng UTF 8 trong nội bộ là sai.

  5. Mã giả định rằng lỗi mã hóa sẽ luôn đưa ra một ngoại lệ là sai.

  6. Mã giả định điểm mã Perl bị giới hạn ở 0x10_FFFF là sai.

  7. Mã giả định rằng bạn có thể đặt $/thành thứ gì đó sẽ hoạt động với bất kỳ dấu tách dòng hợp lệ nào là sai.

  8. Mã giả định bình đẳng khứ hồi trên casefold, như lc(uc($s)) eq $shoặc uc(lc($s)) eq $s, hoàn toàn bị phá vỡ và sai. Hãy xem xét rằng uc("σ")uc("ς") là cả hai "Σ", nhưng lc("Σ")không thể trả lại cả hai.

  9. Mã giả định rằng mỗi điểm mã chữ thường có một chữ hoa riêng biệt hoặc ngược lại, bị hỏng. Ví dụ, "ª"là một chữ cái viết thường không có chữ hoa; trong khi cả hai "ᵃ""ᴬ"là chữ cái, nhưng chúng không phải là chữ thường; tuy nhiên, cả hai đều là điểm mã chữ thường mà không có phiên bản chữ hoa tương ứng. Hiểu chưa Họ không \p{Lowercase_Letter} , mặc dù là cả hai \p{Letter}\p{Lowercase}.

  10. Mã giả định thay đổi trường hợp không thay đổi độ dài của chuỗi bị hỏng.

  11. Mã cho rằng chỉ có hai trường hợp bị phá vỡ. Ngoài ra còn có Titlecase.

  12. Mã giả định chỉ có chữ cái có trường hợp bị phá vỡ. Ngoài các chữ cái, hóa ra các con số, ký hiệu và thậm chí các dấu có trường hợp. Trong thực tế, thay đổi trường hợp thậm chí có thể làm cho một cái gì đó thay đổi danh mục chung chính của nó, giống như \p{Mark}biến thành một \p{Letter}. Nó cũng có thể làm cho nó chuyển từ tập lệnh này sang tập lệnh khác.

  13. Mã giả định rằng trường hợp không bao giờ phụ thuộc vào địa phương bị phá vỡ.

  14. Mã giả định Unicode cung cấp một con số về các địa điểm POSIX bị hỏng.

  15. Mã giả định rằng bạn có thể loại bỏ các dấu phụ để nhận được các chữ cái ASCII cơ bản là xấu xa, tĩnh lặng, bị hỏng, bị tổn thương não, sai và biện minh cho hình phạt tử hình.

  16. Mã giả định rằng dấu phụ \p{Diacritic}và dấu \p{Mark}là cùng một thứ bị phá vỡ.

  17. Mã giả định \p{GC=Dash_Punctuation}bao gồm nhiều như \p{Dash}bị phá vỡ.

  18. Mã giả định dấu gạch ngang, dấu gạch ngang và dấu trừ là giống nhau hoặc chỉ có một trong số đó, bị hỏng và sai.

  19. Mã giả định rằng mọi điểm mã chiếm không quá một cột in bị hỏng.

  20. Mã giả định rằng tất cả các \p{Mark}ký tự chiếm các cột in bằng 0 bị hỏng.

  21. Mã mà giả định rằng nhân vật mà giống nhau như nhau được chia.

  22. Mã mà giả định rằng nhân vật mà ta không giống nhau là không giống nhau được chia.

  23. Mã giả định rằng có một giới hạn về số lượng điểm mã trong một hàng mà chỉ một điểm \Xcó thể khớp là sai.

  24. Mã giả định \Xkhông bao giờ có thể bắt đầu với một \p{Mark}ký tự là sai.

  25. Mã giả định rằng \Xkhông bao giờ có thể chứa hai \p{Mark}ký tự không phải là sai.

  26. Mã giả định rằng nó không thể sử dụng "\x{FFFF}"là sai.

  27. Mã giả định một điểm mã không phải BMP yêu cầu hai đơn vị mã UTF-16 (thay thế) sẽ mã hóa thành hai ký tự UTF-8 riêng biệt, một ký tự cho mỗi đơn vị mã, là sai. Nó không: nó mã hóa thành điểm mã duy nhất.

  28. Mã chuyển mã từ UTF ‐ 16 hoặc UTF ‐ 32 với các BOM hàng đầu thành UTF ‐ 8 bị phá vỡ nếu nó đặt BOM khi bắt đầu UTF-8 kết quả. Điều này thật ngu ngốc các kỹ sư nên loại bỏ mí mắt của họ.

  29. Mã giả định CESU-8 là mã hóa UTF hợp lệ là sai. Tương tự, mã cho rằng mã hóa U + 0000 như "\xC0\x80"UTF-8 bị hỏng và sai. Những kẻ này cũng xứng đáng được điều trị mí mắt.

  30. Mã giả định các ký tự như >luôn luôn chỉ về bên phải và <luôn chỉ về bên trái là sai - vì thực tế chúng không như vậy.

  31. Mã giả định nếu bạn xuất ký tự đầu tiên Xvà sau đó là ký tự Y, những mã đó sẽ hiển thị XYlà sai. Đôi khi họ không.

  32. Mã cho rằng ASCII đủ tốt để viết tiếng Anh đúng là ngu ngốc, thiển cận, mù chữ, đổ vỡ, xấu xa và sai trái. Tắt với cái đầu của họ! Nếu điều đó có vẻ quá cực đoan, chúng ta có thể thỏa hiệp: từ đó họ có thể chỉ gõ bằng ngón chân cái từ một chân. (Phần còn lại sẽ được ghi âm.)

  33. Mã giả định rằng tất cả các \p{Math}điểm mã là các ký tự hiển thị là sai.

  34. Mã giả định \wchỉ chứa các chữ cái, chữ số và dấu gạch dưới là sai.

  35. Mã giả định rằng ^~là dấu chấm câu là sai.

  36. Mã giả định rằng ücó một âm sắc là sai.

  37. Mã tin rằng những thứ như chứa bất kỳ chữ cái nào trong đó là sai.

  38. Mã mà tin \p{InLatin}là giống như \p{Latin}bị phá vỡ mạnh mẽ.

  39. Mã tin rằng \p{InLatin}gần như hữu ích là gần như chắc chắn sai.

  40. Mã tin rằng được đưa ra $FIRST_LETTERnhư là chữ cái đầu tiên trong một số bảng chữ cái và $LAST_LETTERlà chữ cái cuối cùng trong cùng một bảng chữ cái, [${FIRST_LETTER}-${LAST_LETTER}]có bất kỳ ý nghĩa nào gần như luôn luôn hoàn toàn bị phá vỡ và sai và vô nghĩa.

  41. Mã tin rằng tên của ai đó chỉ có thể chứa một số ký tự nhất định là ngu ngốc, gây khó chịu và sai.

  42. Mã cố gắng giảm Unicode thành ASCII không chỉ sai, thủ phạm không bao giờ được phép làm việc trong lập trình lại. Giai đoạn = Stage. Tôi thậm chí không tích cực, họ thậm chí còn được phép gặp lại, vì rõ ràng điều đó đã không làm họ tốt cho đến nay.

  43. Mã tin rằng có một số cách để giả vờ mã hóa văn bản không tồn tại là bị hỏng và nguy hiểm. Cũng có thể thò mắt ra ngoài nữa.

  44. Mã chuyển đổi các ký tự không xác định thành ?bị hỏng, ngu ngốc, bản lĩnh và chạy ngược lại với khuyến nghị tiêu chuẩn, nói rằng KHÔNG NÊN LÀM ĐIỀU NÀY! RTFM tại sao không.

  45. Mã tin rằng nó có thể đoán được một cách đáng tin cậy mã hóa của một tệp văn bản không được đánh dấu là có tội với một mélange gây tử vong của hubris và naïveté mà chỉ một tia sét từ Zeus sẽ sửa chữa.

  46. Mã tin rằng bạn có thể sử dụng 🐪 printfđộ rộng để đệm và chứng minh dữ liệu Unicode bị hỏng và sai.

  47. Mã tin rằng một khi bạn tạo thành công một tệp theo một tên cụ thể, rằng khi bạn chạy lshoặc readdirtrên thư mục kèm theo của nó, bạn sẽ thực sự thấy tệp đó với tên bạn đã tạo ra bị lỗi, bị hỏng và sai. Đừng ngạc nhiên về điều này!

  48. Mã tin rằng UTF-16 là mã hóa có chiều rộng cố định là ngu ngốc, bị hỏng và sai. Thu hồi giấy phép lập trình của họ.

  49. Mã xử lý các điểm mã từ một mặt phẳng khác nhau so với các mã từ bất kỳ mặt phẳng nào khác là ipso facto bị hỏng và sai. Quay trở lại trường học

  50. Mã tin rằng những thứ như /s/ichỉ có thể khớp "S"hoặc "s"bị hỏng và sai. Bạn sẽ ngạc nhiên.

  51. Mã sử ​​dụng \PM\pM*để tìm các cụm grapheme thay vì sử dụng \Xbị hỏng và sai.

  52. Những người muốn quay trở lại thế giới ASCII nên hết lòng khuyến khích làm điều đó, và để tôn vinh sự nâng cấp vẻ vang của họ, họ nên được cung cấp miễn phí một máy đánh chữ thủ công tiền điện cho tất cả các nhu cầu nhập dữ liệu của họ. Tin nhắn được gửi cho họ phải được gửi qua điện báo với 40 ký tự trên mỗi dòng và được chuyển phát bằng tay bởi một người chuyển phát nhanh. DỪNG LẠI.


𝕾 𝖀 𝕸 𝕬 𝕽 𝖄 😱


Tôi không biết bạn có thể nhận được bao nhiêu Unicode mặc định trong Unicode so với những gì tôi đã viết. Vâng, vâng tôi làm: bạn cũng nên sử dụng Unicode::CollateUnicode::LineBreak. Và có lẽ nhiều hơn nữa.

Như bạn thấy, có quá nhiều điều Unicode mà bạn thực sự làm phải lo lắng về cho có bao giờ tồn tại bất cứ điều gì như “mặc định để Unicode”.

Những gì bạn sẽ khám phá, giống như chúng tôi đã làm trong 🐪 5,8, rằng đơn giản là không thể áp đặt tất cả những điều này lên mã đã được thiết kế ngay từ đầu để tính đến chúng. Sự ích kỷ có ý nghĩa tốt của bạn chỉ phá vỡ toàn bộ thế giới.

Và ngay cả khi bạn đã làm, vẫn có những vấn đề quan trọng đòi hỏi rất nhiều suy nghĩ để làm đúng. Không có công tắc bạn có thể lật. Không có gì ngoài bộ não, và ý tôi là bộ não thực sự , sẽ đủ ở đây. Có rất nhiều thứ bạn phải học. Modulo rút lui vào máy đánh chữ thủ công, bạn chỉ đơn giản là không thể hy vọng lẻn vào trong sự thiếu hiểu biết. Đây là thế kỷ 21 và bạn không thể bỏ qua Unicode bằng sự thờ ơ cố ý.

Bạn phải học nó Giai đoạn = Stage. Sẽ không bao giờ dễ dàng đến mức mọi thứ chỉ hoạt động được, vì điều đó sẽ đảm bảo rằng rất nhiều thứ không hoạt động - điều đó vô hiệu hóa giả định rằng có thể có một cách nào đó để làm cho tất cả hoạt động.

Bạn có thể có được một vài giá trị mặc định hợp lý cho một số hoạt động rất hạn chế và rất hạn chế, nhưng không phải không nghĩ về những thứ nhiều hơn tôi nghĩ bạn có.

Chỉ là một ví dụ, trật tự kinh điển sẽ gây ra một số đau đầu thực sự. 😭 "\x{F5}" 'õ' , "o\x{303}" 'õ' , "o\x{303}\x{304}" 'ȭ'"o\x{304}\x{303}" 'ō̃' tất cả nên khớp với 'õ' , nhưng bạn sẽ làm thế nào trên thế giới? Điều này khó hơn vẻ ngoài của nó, nhưng đó là điều bạn cần tính đến. 💣

Nếu có một điều tôi biết về Perl, đó là những gì các bit Unicode của nó làm và không làm, và điều này tôi hứa với bạn: Hồi ̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ s̲ɪ̲ ̲ɴ̲ᴏ̲ U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲

Bạn không thể thay đổi một số mặc định và có được thuận buồm xuôi gió. Đúng là tôi chạy 🐪 vớiPERL_UNICODE cài đặt "SA", nhưng đó là tất cả, và thậm chí đó hầu hết chỉ dành cho công cụ dòng lệnh. Đối với công việc thực tế, tôi trải qua tất cả các bước được nêu ở trên, và tôi làm nó rất, ** rất ** cẩn thận.


😈 ¡dləɥ ƨᴉɥʇ doɥ puɐ p əɔᴉu ɐ əʌɐɥ nl poo⅁


56
Giống như Sherm Pendley chỉ: "Tất cả!". Nếu hôm nay tôi viết một cái gì đó mới, UTF-8 sẽ là cách dễ nhất để hoàn thành công việc. Không phải vậy. Nồi hơi của bạn proove nó. Không phải ai cũng có kiến ​​thức như vậy để biến rất nhiều người lật đổ sang đúng vị trí. Tôi xin lỗi, tôi đã có một ngày dài và khó khăn, vì vậy tôi sẽ bình luận trong mục chính vào ngày mai nhiều hơn với các ví dụ.
tuần

17
Một kết luận nên rõ ràng từ việc đọc danh sách trên: Đừng gấp trường hợp. Chỉ không. Không bao giờ. Tính toán đắt đỏ và với ngữ nghĩa phụ thuộc chủ yếu vào bất cứ điều gì mà "địa phương" cố gắng không thành công để xác định.
Tim Bray

72
Tôi có phải là người duy nhất thấy mỉa mai rằng bài đăng này của tchrist thể hiện rất khác biệt trên FF / Chrome / IE / Opera, đôi khi đến mức không thể đọc được?
Damboy

15
Mặc dù tôi thường thích bài đăng và đã upvote, nhưng có một điều làm tôi khó chịu. Có rất nhiều "mã bị ... bị hỏng". Trong khi tôi không tranh luận với tuyên bố, tôi nghĩ sẽ tốt khi thể hiện sự tan vỡ. Theo cách này, nó sẽ đi qua (phần này của câu trả lời) từ một lời nói, đến giáo dục.

36
@xenoterracide Không Tôi không sử dụng các điểm mã có vấn đề cố ý; đó là một âm mưu để giúp bạn cài đặt phông chữ Symbola siêu tuyệt vời của George Douros , bao gồm Unicode 6.0. @Depesz Không có chỗ ở đây để giải thích tại sao mỗi giả định bị hỏng là sai. @leonbloy Rất nhiều và rất nhiều điều này áp dụng cho Unicode nói chung, không chỉ Perl. Một số tài liệu này có thể xuất hiện trong 🐪 Lập trình Perl, phiên bản thứ 4 , dự kiến ​​ra mắt vào tháng Mười. Tôi còn một tháng để ✍ làm việc với nó và Unicode là ở đó; regexes cũng vậy
tchrist

96

Có hai giai đoạn để xử lý văn bản Unicode. Đầu tiên là "làm thế nào tôi có thể nhập nó và xuất nó mà không mất thông tin". Thứ hai là "làm thế nào để tôi đối xử với văn bản theo quy ước ngôn ngữ địa phương".

bài đăng của tchrist bao gồm cả hai, nhưng phần thứ hai là nơi 99% văn bản trong bài viết của ông đến từ. Hầu hết các chương trình thậm chí không xử lý I / O chính xác, vì vậy điều quan trọng là phải hiểu điều đó trước khi bạn bắt đầu lo lắng về việc chuẩn hóa và đối chiếu.

Bài này nhằm giải quyết vấn đề đầu tiên đó

Khi bạn đọc dữ liệu vào Perl, nó không quan tâm mã hóa nó là gì. Nó phân bổ một số bộ nhớ và bỏ các byte ở đó. Nếu bạn nóiprint $str , nó chỉ làm mờ các byte đó ra thiết bị đầu cuối của bạn, có thể được đặt để giả sử mọi thứ được ghi vào nó là UTF-8 và văn bản của bạn hiển thị.

Kỳ diệu.

Ngoại trừ, không phải vậy. Nếu bạn cố gắng coi dữ liệu là văn bản, bạn sẽ thấy có gì đó không hay đang xảy ra. Bạn không cần phải đi xa hơn lengthđể thấy rằng những gì Perl nghĩ về chuỗi của bạn và những gì bạn nghĩ về chuỗi của bạn không đồng ý. Viết một lớp lót như: perl -E 'while(<>){ chomp; say length }'và gõ vào文字化け và bạn nhận được 12 ... không phải là câu trả lời đúng, 4.

Đó là bởi vì Perl giả định chuỗi của bạn không phải là văn bản. Bạn phải nói với nó rằng đó là văn bản trước khi nó đưa ra câu trả lời đúng.

Điều đó đủ dễ dàng; mô-đun Encode có các chức năng để làm điều đó. Điểm vào chung là Encode::decode(hoặcuse Encode qw(decode) , tất nhiên). Hàm đó lấy một số chuỗi từ thế giới bên ngoài (cái mà chúng ta gọi là "octet", một cách nói lạ mắt là "byte 8 bit") và biến nó thành một số văn bản mà Perl sẽ hiểu. Đối số đầu tiên là tên mã hóa ký tự, như "UTF-8" hoặc "ASCII" hoặc "EUC-JP". Đối số thứ hai là chuỗi. Giá trị trả về là vô hướng Perl chứa văn bản.

(Ngoài ra Encode::decode_utf8, giả sử UTF-8 cho mã hóa.)

Nếu chúng ta viết lại một lớp lót của chúng tôi:

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

Chúng tôi gõ vào 字 và nhận được "4" là kết quả. Sự thành công.

Điều đó, ngay tại đó, là giải pháp cho 99% các vấn đề về Unicode trong Perl.

Điều quan trọng là, bất cứ khi nào bất kỳ văn bản nào đi vào chương trình của bạn, bạn phải giải mã nó. Internet không thể truyền ký tự. Tập tin không thể lưu trữ các ký tự. Không có ký tự trong cơ sở dữ liệu của bạn. Chỉ có các octet và bạn không thể coi các octet là các ký tự trong Perl. Bạn phải giải mã các octet được mã hóa thành các ký tự Perl bằng mô-đun Encode.

Nửa còn lại của vấn đề là lấy dữ liệu ra khỏi chương trình của bạn. Điều đó thật dễ dàng; bạn chỉ cần nói use Encode qw(encode), quyết định mã hóa dữ liệu của bạn sẽ ở đâu (UTF-8 đến các thiết bị đầu cuối hiểu UTF-8, UTF-16 cho các tệp trên Windows, v.v.), sau đó xuất kết quả encode($encoding, $data)thay vì chỉ xuất ra $data.

Hoạt động này chuyển đổi các ký tự của Perl, đó là những gì chương trình của bạn hoạt động, thành các octet có thể được sử dụng bởi thế giới bên ngoài. Sẽ dễ dàng hơn rất nhiều nếu chúng ta chỉ có thể gửi các ký tự qua Internet hoặc đến các thiết bị đầu cuối của mình, nhưng chúng ta không thể: chỉ các octet. Vì vậy, chúng tôi phải chuyển đổi các ký tự thành octet, nếu không kết quả là không xác định.

Để tóm tắt: mã hóa tất cả các đầu ra và giải mã tất cả các đầu vào.

Bây giờ chúng ta sẽ nói về ba vấn đề khiến điều này trở nên khó khăn. Đầu tiên là thư viện. Họ có xử lý văn bản chính xác? Câu trả lời là ... họ cố gắng. Nếu bạn tải xuống một trang web, LWP sẽ cung cấp cho bạn kết quả của bạn dưới dạng văn bản. Nếu bạn gọi đúng phương thức trên kết quả, nghĩa là (và điều đó xảy ra decoded_content, không phải content, đó chỉ là luồng octet mà nó nhận được từ máy chủ.) Trình điều khiển cơ sở dữ liệu có thể bị rung; nếu bạn sử dụng DBD :: SQLite chỉ với Perl, nó sẽ hoạt động, nhưng nếu một số công cụ khác đã đặt văn bản được lưu trữ dưới dạng mã hóa khác với UTF-8 trong cơ sở dữ liệu của bạn ... thì ... nó sẽ không được xử lý chính xác cho đến khi bạn viết mã để xử lý nó một cách chính xác

Xuất dữ liệu thường dễ dàng hơn, nhưng nếu bạn thấy "ký tự rộng in", thì bạn biết bạn đang làm rối mã hóa ở đâu đó. Cảnh báo đó có nghĩa là "này, bạn đang cố gắng rò rỉ các nhân vật Perl ra thế giới bên ngoài và điều đó không có ý nghĩa gì cả". Chương trình của bạn có vẻ hoạt động (vì đầu kia thường xử lý chính xác các ký tự Perl), nhưng nó rất bị hỏng và có thể ngừng hoạt động bất cứ lúc nào. Sửa chữa nó với một rõ ràng Encode::encode!

Vấn đề thứ hai là mã nguồn được mã hóa UTF-8. Trừ khi bạn nói use utf8ở đầu mỗi tệp, Perl sẽ không cho rằng mã nguồn của bạn là UTF-8. Điều này có nghĩa là mỗi lần bạn nói điều gì đó như my $var = 'ほげ', bạn đang bơm rác vào chương trình của mình, điều đó sẽ phá vỡ mọi thứ một cách khủng khiếp. Bạn không cần phải "sử dụng utf8", nhưng nếu bạn không, bạn phải không sử dụng bất kỳ ký tự khác ASCII trong chương trình của bạn.

Vấn đề thứ ba là làm thế nào Perl xử lý Quá khứ. Cách đây rất lâu, không có thứ gì như Unicode và Perl cho rằng mọi thứ đều là văn bản hoặc nhị phân Latin-1. Vì vậy, khi dữ liệu đi vào chương trình của bạn và bạn bắt đầu coi nó là văn bản, Perl coi mỗi octet là một ký tự Latin-1. Đó là lý do tại sao, khi chúng tôi hỏi về độ dài của "", chúng tôi đã nhận được 12. Perl cho rằng chúng tôi đang hoạt động trên chuỗi Latin-1 "æååã" (gồm 12 ký tự, một số ký tự không in).

Đây được gọi là "nâng cấp ngầm" và đó là một điều hoàn toàn hợp lý để làm, nhưng đó không phải là điều bạn muốn nếu văn bản của bạn không phải là tiếng Latin-1. Đó là lý do tại sao việc giải mã một cách rõ ràng đầu vào: nếu bạn không làm điều đó, Perl sẽ làm và nó có thể làm sai.

Mọi người gặp rắc rối trong đó một nửa dữ liệu của họ là một chuỗi ký tự phù hợp và một số vẫn là nhị phân. Perl sẽ diễn giải phần vẫn là nhị phân như thể văn bản Latin-1 và sau đó kết hợp nó với dữ liệu ký tự chính xác. Điều này sẽ làm cho việc xử lý các nhân vật của bạn phá vỡ chương trình của bạn một cách chính xác, nhưng thực tế, bạn chỉ chưa sửa nó đủ.

Đây là một ví dụ: bạn có một chương trình đọc tệp văn bản được mã hóa UTF-8, bạn xử lý Unicode PILE OF POOtrên mỗi dòng và bạn in nó ra. Bạn viết nó như sau:

while(<>){
    chomp;
    say "$_ 💩";
}

Và sau đó chạy trên một số dữ liệu được mã hóa UTF-8, như:

perl poo.pl input-data.txt

Nó in dữ liệu UTF-8 với một poo ở cuối mỗi dòng. Hoàn hảo, chương trình của tôi hoạt động!

Nhưng không, bạn chỉ đang thực hiện nối nhị phân. Bạn đang đọc octet từ tệp, xóa a \nbằng chomp và sau đó xử lý các byte trong biểu diễn UTF-8 của PILE OF POOký tự. Khi bạn sửa đổi chương trình của mình để giải mã dữ liệu từ tệp và mã hóa đầu ra, bạn sẽ nhận thấy rằng bạn nhận được rác ("ð ©") thay vì poo. Điều này sẽ khiến bạn tin rằng giải mã tệp đầu vào là điều sai. Nó không thể.

Vấn đề là poo đang được nâng cấp ngầm thành latin-1. Nếu bạn use utf8làm văn bản bằng chữ thay vì nhị phân, thì nó sẽ hoạt động trở lại!

. nó bị hỏng. Đừng lo lắng, nếu bạn đang thêm các câu lệnh mã hóa / giải mã vào chương trình của mình và nó bị hỏng, điều đó chỉ có nghĩa là bạn còn nhiều việc phải làm. dễ dàng hơn nhiều!)

Đó thực sự là tất cả những gì bạn cần biết về Perl và Unicode. Nếu bạn nói với Perl dữ liệu của bạn là gì, nó có hỗ trợ Unicode tốt nhất trong số tất cả các ngôn ngữ lập trình phổ biến. Tuy nhiên, nếu bạn cho rằng nó sẽ kỳ diệu biết loại văn bản bạn đang cho nó ăn, thì bạn sẽ bỏ rác dữ liệu của mình. Chỉ vì chương trình của bạn hoạt động hôm nay trên thiết bị đầu cuối UTF-8 của bạn không có nghĩa là chương trình sẽ hoạt động vào ngày mai trên tệp được mã hóa UTF-16. Vì vậy, hãy làm cho nó an toàn ngay bây giờ và tự cứu mình khỏi việc làm hỏng dữ liệu của người dùng!

Phần dễ dàng của việc xử lý Unicode là mã hóa đầu ra và giải mã đầu vào. Phần khó là tìm tất cả đầu vào và đầu ra của bạn và xác định mã hóa đó là gì. Nhưng đó là lý do tại sao bạn nhận được số tiền lớn :)


Nguyên tắc được giải thích tốt, nhưng cách tiếp cận thực tế cho I / O còn thiếu. Rõ ràng việc sử dụng Encodemô-đun là tẻ nhạt và dễ bị lỗi, và nó làm cho việc đọc mã liên quan đến I / O thực sự đau đớn. Các lớp I / O cung cấp một giải pháp khi chúng mã hóa và giải mã trong suốt, khi cần thiết. openbinmodecho phép đặc điểm kỹ thuật của họ, và pragma openđặt mặc định, như tchrist khuyến nghị trong câu trả lời của mình.
Palec

48

Tất cả chúng ta đều đồng ý rằng đó là một vấn đề khó khăn vì nhiều lý do, nhưng đó chính xác là lý do để cố gắng làm cho mọi người dễ dàng hơn.

Có một mô-đun gần đây trên CPAN, utf8 :: all , cố gắng "bật Unicode. Tất cả của nó".

Như đã chỉ ra, bạn không thể làm cho toàn bộ hệ thống (các chương trình bên ngoài, yêu cầu web bên ngoài, v.v.) sử dụng Unicode một cách kỳ diệu, nhưng chúng ta có thể làm việc cùng nhau để tạo ra các công cụ hợp lý giúp thực hiện các vấn đề phổ biến dễ dàng hơn. Đó là lý do mà chúng tôi lập trình viên.

Nếu utf8 :: tất cả không làm điều gì bạn nghĩ là nên làm, hãy cải thiện nó để làm cho nó tốt hơn. Hoặc hãy tạo ra các công cụ bổ sung cùng nhau có thể phù hợp với nhu cầu khác nhau của mọi người cũng như có thể.

`


5
Tôi thấy rất nhiều chỗ để cải thiện trong utf8::allmô-đun được trích dẫn . Nó được viết trước unicode_stringstính năng, mà Fɪɴᴀʟʟʏ ᴀɴᴅ Lᴏɴɢ Lᴀsᴛ sửa các biểu thức để có một /utrên chúng. Tôi không tin nó làm tăng ngoại lệ về lỗi mã hóa và đó là điều bạn thực sự phải có. Nó không tải trong use charnames ":full"pragma, chưa được tự động tải. Nó không cảnh báo [a-z]và như vậy, printfđộ rộng chuỗi, sử dụng \nthay vì \R.thay vì \X, nhưng có lẽ đó là Perl::Criticvấn đề quan trọng hơn. Nếu là tôi, tôi sẽ thêm vào và ra.
tchrist

13
@tchrist Trình theo dõi vấn đề cho utf8 :: tất cả đều có ở đây. github.com/doherty/utf8-all/issues Họ rất thích nghe đề xuất của bạn.
Schwern

4
@Schwern: ᴇɴᴏᴛᴜɪᴛs, nhưng cứ thoải mái ăn cắp và véo từ những thứ tôi đã viết ở đây. Thành thật mà nói, tôi vẫn đang cảm thấy / học hỏi những gì có thể được thực hiện so với những gì nên làm và ở đâu. Đây là một ví dụ hay về sắp xếp giảm tải : unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r. Tương tự, các bước tiền xử lý nhỏ như thế ... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'cũng có thể thực sự tốt và tôi không muốn đưa ra quyết định cho người khác. Tôi vẫn đang xây dựng hộp công cụ Unicode của mình .
tchrist

35

Tôi nghĩ bạn hiểu nhầm Unicode và mối quan hệ của nó với Perl. Cho dù bạn lưu trữ dữ liệu theo cách nào, Unicode, ISO-8859-1 hay nhiều thứ khác, chương trình của bạn phải biết cách diễn giải các byte mà nó nhận được như là đầu vào (giải mã) và cách thể hiện thông tin mà nó muốn xuất ra (mã hóa ). Nhận giải thích sai và bạn cắt xén dữ liệu. Không có một số thiết lập mặc định kỳ diệu nào trong chương trình của bạn, điều đó sẽ nói cho những thứ bên ngoài chương trình của bạn cách hành động.

Bạn nghĩ rằng nó rất khó, rất có thể, bởi vì bạn đã quen với mọi thứ là ASCII. Tất cả mọi thứ bạn nên nghĩ về chỉ đơn giản là bị bỏ qua bởi ngôn ngữ lập trình và tất cả những thứ nó phải tương tác. Nếu mọi thứ không sử dụng gì ngoài UTF-8 và bạn không có lựa chọn nào khác, thì UTF-8 sẽ dễ dàng như vậy. Nhưng không phải mọi thứ đều sử dụng UTF-8. Chẳng hạn, bạn không muốn xử lý đầu vào của mình nghĩ rằng nó đang nhận các octet UTF-8 trừ khi thực tế và bạn không muốn các xử lý đầu ra của mình là UTF-8 nếu việc đọc từ chúng có thể xử lý UTF-8 . Perl không có cách nào để biết những điều đó. Đó là lý do tại sao bạn là lập trình viên.

Tôi không nghĩ Unicode trong Perl 5 quá phức tạp. Tôi nghĩ nó đáng sợ và mọi người tránh nó. Có một sự khác biệt. Cuối cùng, tôi đã đưa Unicode vào Học Perl, Phiên bản thứ 6 và có rất nhiều nội dung Unicode trong Lập trình Perl hiệu quả . Bạn phải dành thời gian để tìm hiểu và hiểu về Unicode và cách thức hoạt động của nó. Bạn sẽ không thể sử dụng nó một cách hiệu quả.


3
Tôi nghĩ rằng bạn có một điểm: nó thật đáng sợ. Nó phải được? Đối với tôi là phước lành Unicode, sử dụng nó trong Perl5 thì không (tôi không cho rằng bất cứ điều gì là ASCII, tiếng mẹ đẻ của tôi cần ít nhất là iso8859-4). Tôi đã cài đặt Rakudo và mọi thứ tôi đã thử với UTF-8 (trong hộp cát giới hạn này) đều hoạt động tốt. Tôi có bỏ lỡ điều gì không? Tôi nhấn mạnh một lần nữa: thật tốt khi có hỗ trợ Unicode được điều chỉnh tốt, nhưng trên hầu hết thời gian là không cần điều đó. Để tránh xa chủ đề, một cách là mọi người đọc rất nhiều để hiểu nội bộ. Khác: chúng tôi có pragma đặc biệt, vì vậy use utf8_everywherelàm cho mọi người hạnh phúc. Tại sao không phải là cuối cùng?
tuần

3
Tôi vẫn nghĩ rằng bạn đang thiếu điểm. Những gì đã làm việc? Bạn không cần phải hiểu nội bộ. Bạn cần hiểu các phần bên ngoài và cách bạn muốn xử lý các chuỗi có mã hóa khác nhau và các cách biểu diễn khác nhau của cùng một ký tự. Đọc lời khuyên của Tom một lần nữa. Hầu hết những gì anh ấy nói tôi cá là bạn sẽ thấy Rakudo không xử lý cho bạn.
brian d foy

1
@wk: Đọc lại câu trả lời của Randy. Anh ấy đã nói với bạn những hạn chế là gì.
brian d foy

2
@brian d foy: Tôi nghĩ rằng những hạn chế đó là tốt, như tchrist nói, không có viên đạn ma thuật nào cho mọi khía cạnh (tôi thừa nhận: tôi đã không thấy hầu hết trong số họ trước khi hỏi câu hỏi này ở đây). Vì vậy, khi chúng tôi bao gồm rất nhiều công cụ cơ bản với một cái gì đó như utf8 :: tất cả, không cần tất cả mọi người xây dựng nồi hơi khổng lồ của riêng mình chỉ để có được những điều cơ bản về xử lý utf8 để hoạt động. Với "không sợ gì cả" ý tôi là: mọi người đều có thể bắt đầu các dự án của mình khi biết rằng những điều cơ bản được bảo hiểm. Vâng, bạn đã đúng, vẫn còn rất nhiều vấn đề. Nhưng khi bắt đầu dễ dàng hơn, chúng ta sẽ có nhiều người tham gia giải quyết những điều đó. IMHO
wk

1
@wk - "sai" duy nhất với "utf8: all" hoặc "uni :: perl chỉ là một - họ không ở trong CORE - vì vậy mọi người phải cài đặt nó từ CPAN. Và nếu bạn nghĩ rằng điều này không phải là lớn thỏa thuận - hãy suy nghĩ lại - vâng, sử dụng utf8 dễ dàng hơn với mô-đun trợ giúp. Không có nó, CORE perl vẫn có hỗ trợ unicode - nhưng rất nhiều phức tạp. Và điều này là sai.
jm666

28

Trong khi đọc chủ đề này, tôi thường có ấn tượng rằng mọi người đang sử dụng " UTF-8 " như một từ đồng nghĩa với " Unicode ". Vui lòng phân biệt giữa "Điểm mã" của Unicode, là họ hàng mở rộng của mã ASCII và "mã hóa" khác nhau của Unicode. Và có một vài trong số đó, trong đó UTF-8, UTF-16UTF-32 là những cái hiện tại và một số ít nữa đã lỗi thời.

Xin vui lòng, UTF-8 (cũng như tất cả các bảng mã khác ) tồn tại và chỉ có ý nghĩa trong đầu vào hoặc đầu ra. Trong nội bộ, kể từ Perl 5.8.1, tất cả các chuỗi được giữ dưới dạng "Điểm mã" Unicode. Đúng, bạn phải kích hoạt một số tính năng như được bao phủ một cách đáng ngưỡng mộ trước đây.


19
Tôi đồng ý mọi người thường nhầm lẫn Uɴɪᴄᴏᴅᴇ với UTF-8⧸16⧸32, nhưng về cơ bản và cực kỳ không đúng là Uɴɪᴄᴏᴅᴇ chỉ là một số ký tự được phóng to so với sᴄɪɪ. Nhiều nhất, đó không gì khác hơn là sɪ ‑ 10646 . Uɴɪᴄᴏᴅᴇ bao gồm nhiều hơn : quy tắc đối chiếu, ghép hình, biểu mẫu chuẩn hóa, cụm grapheme, ngắt dòng và chữ viết, tập lệnh, phương trình số, độ rộng, hai chiều, biến thể glyph, hành vi ngữ cảnh, địa phương, biểu thức, lớp kết hợp, 100 thuộc tính, nhiều hơn nữa‼
tchrist

15
@tchrist: bước đầu tiên là đưa dữ liệu vào chương trình của bạn và ra thế giới bên ngoài mà không bỏ rác. sau đó bạn có thể lo lắng về đối chiếu, trường hợp gấp, biến thể glyph, vv các bước bé.
jrockway

7
Tôi đồng ý, nhận được perl không vào đầu vào hoặc đầu ra rác phải là ưu tiên hàng đầu. Điều tôi muốn là có một mô-đun hoặc pragma có thể thể hiện cuộc trò chuyện giả tưởng sau đây: "- Perl thân mến. Đối với chương trình này, tất cả đầu vào và đầu ra sẽ chỉ là UTF-8. Bạn có thể không làm hỏng dữ liệu của tôi không? - Vì vậy, chỉ có bạn nói UFT-8. Bạn có chắc không? - Vâng - Thực sự, thực sự chắc chắn? - Hoàn toàn. - Và bạn chấp nhận rằng tôi có thể cư xử kỳ lạ nếu tôi được phục vụ dữ liệu không phải UTF-8? - Vâng, tốt. - Được rồi. "
hlovdal

10

Có một số lượng mã cổ thực sự khủng khiếp ngoài tự nhiên, phần lớn ở dạng mô-đun CPAN thông thường. Tôi thấy rằng tôi phải khá cẩn thận khi bật Unicode nếu tôi sử dụng các mô-đun bên ngoài có thể bị ảnh hưởng bởi nó và vẫn đang cố gắng xác định và khắc phục một số lỗi liên quan đến Unicode trong một số tập lệnh Perl mà tôi sử dụng thường xuyên (cụ thể là iTiVo không thành công không tốt cho bất cứ điều gì không phải là ASCII 7 bit do vấn đề chuyển mã).


Tôi có nghĩa là sử dụng -Ctùy chọn để đảm bảo Perl ở cùng trang với tôi là người khôn ngoan về Unicode, bởi vì tôi vẫn quyết định sử dụng ISO 8859/1 thay vì Unicode mặc dù tôi đã cài đặt rõ ràng $LANG$LC_ALLđúng cách. .
geekizard

3
Một mình -Ckhông có tùy chọn là lỗi và dễ bị lỗi . Bạn phá vỡ thế giới. Đặt mức PERL5OPTđộ phù hợp -Cvà bạn sẽ thấy những gì tôi muốn nói. Chúng tôi đã thử cách này trở lại trong v5.8, và đó là một thảm họa. Bạn chỉ đơn giản là không thể và không được nói với các chương trình không mong đợi rằng bây giờ họ đang xử lý Unicode dù họ có thích hay không. Ngoài ra còn có vấn đề bảo mật. Ít nhất, bất cứ điều gì print while <>sẽ phá vỡ nếu thông qua dữ liệu nhị phân. Tất cả các mã cơ sở dữ liệu cũng vậy. Đây là một ý tưởng khủng khiếp.
tchrist

1
Tôi đã nói một cách khái quát, thực sự, không cụ thể -Cmà không có lựa chọn. Yêu cầu cụ thể mà tôi đã làm việc với là -CSDA. Điều đó nói rằng, tôi đã bị mắc kẹt với 5.8.x trong một thời gian dài (xin chào MacPorts ...), vì vậy có lẽ đó một phần của nó.
geekizard

1
Tôi chạy với PERL_UNICODE được đặt thành SA. Bạn KHÔNG THỂ đặt nó thành D.
tchrist

@tchrist: Một số varmint Perl đã được đăng mã hiển thị việc sử dụng -CSDA và PERL_UNICODE = SDA . Vui lòng sử dụng ảnh hưởng của bạn trong cộng đồng. Anh phải dừng lại!
Ashley

1

Bạn nên kích hoạt tính năng chuỗi unicode và đây là mặc định nếu bạn sử dụng v5,14;

Bạn không nên thực sự sử dụng định danh unicode đặc biệt. đối với mã nước ngoài thông qua utf8 vì chúng không an toàn trong perl5, chỉ cperl có quyền đó. Xem ví dụ: http://perl11.org/blog/unicode-identifier.html

Về utf8 cho tập tin / luồng của bạn: Bạn cần tự mình quyết định mã hóa dữ liệu ngoài của mình. Một thư viện không thể biết điều đó, và vì thậm chí libc không hỗ trợ utf8, dữ liệu utf8 thích hợp là rất hiếm. Có nhiều wtf8 hơn, các cửa sổ quang sai của utf8 xung quanh.

BTW: Moose không thực sự là "Modern Perl", họ chỉ chiếm đoạt tên. Moose hoàn hảo theo phong cách hậu hiện đại của Larry Wall pha trộn với mọi thứ theo kiểu Bjarne Stroustrup, với một quang sai chiết trung của cú pháp perl6 thích hợp, ví dụ như sử dụng chuỗi cho tên biến, cú pháp trường khủng khiếp và triển khai ngây thơ rất non nớt, chậm hơn 10 lần so với thực hiện đúng. cperl và perl6 là các perls hiện đại thực sự, trong đó biểu mẫu tuân theo chức năng và việc thực hiện được giảm thiểu và tối ưu hóa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.