ทำไม Perl สมัยใหม่หลีกเลี่ยง UTF-8 โดยค่าเริ่มต้น


557

ฉันสงสัยว่าทำไมโซลูชั่นที่ทันสมัยที่สุดที่สร้างโดยใช้ Perl ไม่เปิดใช้งานUTF-8โดยค่าเริ่มต้น

ฉันเข้าใจว่ามีปัญหาแบบดั้งเดิมสำหรับสคริปต์ Perl หลักซึ่งอาจทำให้เกิดปัญหา แต่จากมุมมองของฉันใน 21 เซนต์ศตวรรษโครงการขนาดใหญ่ใหม่ (หรือโครงการที่มีมุมมองขนาดใหญ่) ควรทำให้ซอฟต์แวร์ UTF-8 ของพวกเขาพิสูจน์จากรอยขีดข่วน ยังฉันไม่เห็นมันเกิดขึ้น ยกตัวอย่างเช่นMooseช่วยให้เข้มงวดและคำเตือน แต่ไม่Unicode โมเดิร์น :: Perlช่วยลดสำเร็จรูปสำเร็จรูป แต่ไม่มี UTF-8 จัดการ

ทำไม? มีเหตุผลบางอย่างที่จะหลีกเลี่ยง UTF-8 ในโครงการ Perl ที่ทันสมัยในปี 2011 หรือไม่?


ความคิดเห็น @tchrist ยาวเกินไปดังนั้นฉันจึงเพิ่มที่นี่

ดูเหมือนว่าฉันไม่ได้ทำให้ตัวเองชัดเจน ให้ฉันลองเพิ่มบางสิ่ง

tchristและฉันเห็นว่าสถานการณ์ค่อนข้างคล้ายคลึงกัน แต่ข้อสรุปของเรานั้นสมบูรณ์ในทางตรงกันข้าม ฉันเห็นด้วยสถานการณ์ของ Unicode นั้นซับซ้อน แต่นี่เป็นเหตุผลว่าทำไมเรา (ผู้ใช้ Perl และ coders) ต้องการเลเยอร์ (หรือ pragma) ซึ่งทำให้การจัดการ UTF-8 เป็นเรื่องง่ายเหมือนทุกวันนี้

tchristชี้ไปหลายแง่มุมเพื่อให้ครอบคลุมฉันจะอ่านและคิดเกี่ยวกับพวกเขาสำหรับวันหรือสัปดาห์ ถึงกระนั้นนี่ไม่ใช่จุดของฉัน tchristพยายามพิสูจน์ว่าไม่มีวิธีเดียว "เพื่อเปิดใช้งาน UTF-8" ฉันไม่มีความรู้มากมายที่จะโต้แย้งกับสิ่งนั้น ดังนั้นฉันจึงติดตัวอย่างสด

ผมเล่นรอบกับRakudoและ UTF-8 เป็นเพียงแค่มีเท่าที่ฉันจำเป็น ฉันไม่ได้มีปัญหาใด ๆ มันก็ทำงานได้ อาจมีข้อ จำกัด บางแห่งที่ลึกกว่านี้ แต่เมื่อเริ่มต้นทั้งหมดที่ฉันทดสอบทำงานได้ตามที่คาดไว้

ไม่ควรที่จะเป็นเป้าหมายใน Perl 5 ที่ทันสมัยด้วยใช่ไหม ฉันเน้นมันมากขึ้น: ฉันไม่แนะนำ UTF-8 เป็นชุดอักขระเริ่มต้นสำหรับ Perl หลักฉันขอแนะนำความเป็นไปได้ที่จะเรียกใช้อย่างรวดเร็วสำหรับผู้ที่พัฒนาโครงการใหม่

อีกตัวอย่างหนึ่ง แต่ด้วยน้ำเสียงที่เป็นลบมากขึ้น กรอบงานควรทำให้การพัฒนาง่ายขึ้น เมื่อหลายปีก่อนฉันลองใช้เว็บเฟรมเวิร์ก แต่เพิ่งโยนมันทิ้งไปเพราะ "การเปิดใช้งาน UTF-8" นั้นช่างคลุมเครือ ฉันไม่พบวิธีการที่จะขอการสนับสนุน Unicode มันใช้เวลานานมากที่ฉันพบว่ามันง่ายกว่าที่จะไปทางเก่า ตอนนี้ฉันเห็นที่นี่มีความโปรดปรานที่จะจัดการกับปัญหาเดียวกันกับMason 2: จะทำให้ Mason2 UTF-8 สะอาดได้อย่างไร . ดังนั้นมันจึงเป็นโครงร่างที่ค่อนข้างใหม่ แต่การใช้งานกับ UTF-8 นั้นต้องการความรู้เชิงลึกเกี่ยวกับการใช้งานภายใน มันเหมือนป้ายแดงขนาดใหญ่: STOP อย่าใช้ฉัน!

ฉันชอบ Perl แต่การรับมือกับ Unicode นั้นเจ็บปวด ฉันยังพบว่าตัวเองวิ่งไปกับกำแพง tchristเป็นวิธีที่ถูกต้องและตอบคำถามของฉัน: โครงการใหม่ไม่ดึงดูด UTF-8 เพราะมันซับซ้อนเกินไปใน Perl 5


15
ฉันขอโทษ แต่ฉันเห็นด้วยกับ @tchrist - UTF-8 นั้นยากมาก ไม่มีกรอบหรือเครื่องมือที่ "พลิกสวิตช์" แล้วจัดการอย่างถูกต้อง เป็นสิ่งที่คุณต้องคำนึงถึงโดยตรงเมื่อออกแบบแอปพลิเคชันของคุณ - ไม่ใช่กรอบหรือภาษาใด ๆ ที่สามารถรองรับคุณได้ หาก rakudo เพิ่งจะทำงานให้กับคุณคุณไม่ได้ผจญภัยมากพอกับกรณีทดสอบของคุณเพราะมันจะต้องใช้หลายตัวอย่างในคำตอบของ @ tchrist และคนขายเนื้อ
Billy ONeal

12
คุณหวังว่า Moose หรือ Modern :: Perl จะทำอะไรกันแน่? ทำให้ข้อมูลอักขระที่เข้ารหัสแบบสุ่มอย่างน่าอัศจรรย์ในไฟล์และฐานข้อมูลเป็นข้อมูลที่ถูกต้องอีกครั้งหรือไม่
jrockway

13
นั่นหมายความว่าอย่างไร? กวางมูซไม่มีอะไรเกี่ยวข้องกับการจัดการข้อความ เหตุใดจึงควรรู้เกี่ยวกับการเข้ารหัสอักขระเลือกตัวเลือกเริ่มต้นสำหรับคุณน้อยกว่ามาก (อย่างไรก็ตามเหตุผลที่รายการ pragmas ที่คุณไม่ได้สัมผัสการเข้ารหัสเป็นเพราะการประชุมสำหรับ Perl pragmas ที่จะส่งผลกระทบต่อพฤติกรรมคำศัพท์สมมติว่าทั้งโลกทั้งโมดูลอื่น ๆ รวมเป็น UTF-8 เป็นเพียงสิ่งผิดที่ต้องทำ นี่ไม่ใช่ PHP หรือ Ruby ที่นี่)
jrockway

8
(นอกจากนี้ ... "โมเดิร์นมากที่สุด Perl ปพลิเคชัน" หยุดบน UTF-8 ฉันได้แน่นอนไม่เคยเขียนโปรแกรม Perl หรืออย่างอื่นที่ไม่ Unicode ทำความสะอาด?.)
jrockway

11
nb tchrist (Tom Christiansen) โพสต์ [ training.perl.com/OSCON2011/index.html เนื้อหาของ Tom Christiansen สำหรับ OSCON 2011] เกี่ยวกับ Unicode หนึ่งในหัวข้อ "Unicode Support Shootout: Good, Bad, & the Ugly (Ugly) ส่วนใหญ่พูดถึงการสนับสนุน Unicode ในภาษาการเขียนโปรแกรมที่แตกต่างกัน เฉพาะ Google Go และ Perl5 เท่านั้นที่รองรับ Unicode อย่างเต็มรูปแบบมีเพียง Google Go ในตัวเท่านั้น (ไม่พูดถึง Perl6)
Jakub Narębski

คำตอบ:


1146

𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚

  1. การตั้งค่าของคุณจะPERL_UNICODE envariable ASสิ่งนี้ทำให้สคริปต์ Perl ทั้งหมดถอดรหัส@ARGVเป็นสตริง UTF ‑ 8 และตั้งค่าการเข้ารหัสของ stdin, stdout และ stderr เป็น UTF ‑ 8 ทั้งสาม ทั้งสองอย่างนี้เป็นเอฟเฟกต์ระดับโลกไม่ใช่คำศัพท์

  2. ที่ด้านบนของซอร์สไฟล์ของคุณ (โปรแกรม, โมดูล, doไลบรารี่, hickey) ให้ยืนยันว่าคุณกำลังรัน perl เวอร์ชั่น 5.12 หรือดีกว่าผ่าน:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
  3. เปิดใช้งานการเตือนเนื่องจากการประกาศก่อนหน้านี้เปิดใช้งานการ จำกัด และคุณลักษณะเท่านั้นไม่ใช่การเตือน ฉันยังแนะนำให้โปรโมตการเตือน Unicode เป็นข้อยกเว้นดังนั้นให้ใช้ทั้งสองบรรทัดเหล่านี้ไม่ใช่หนึ่งในนั้น หมายเหตุอย่างไรก็ตามว่าภายใต้ v5.14 ที่utf8ระดับเตือนประกอบด้วยสาม subwarnings อื่น ๆ ที่สามารถเปิดใช้งานทั้งหมดจะถูกแยกnonchar, และsurrogate non_unicodeสิ่งเหล่านี้คุณอาจต้องการออกแรงควบคุมมากกว่านี้

    use warnings;
    use warnings qw( FATAL utf8 );
  4. ประกาศว่าหน่วยต้นทางนี้เข้ารหัสเป็น UTF ‑ 8 แม้ว่ากาลครั้งหนึ่งนานมาแล้วที่สิ่งนี้จะทำสิ่งอื่น pragma ตอนนี้มันทำหน้าที่วัตถุประสงค์เดียวเอกพจน์นี้คนเดียวและอื่น ๆ :

    use utf8;
  5. ประกาศว่าสิ่งใดก็ตามที่เปิด filehandle ภายในขอบเขตศัพท์นี้ แต่ไม่ได้อยู่ที่อื่นจะถือว่าสตรีมนั้นถูกเข้ารหัสใน UTF ‑ 8 เว้นแต่คุณจะบอกเป็นอย่างอื่น ด้วยวิธีนี้คุณจะไม่ส่งผลกระทบต่อโค้ดของโมดูลหรือโปรแกรมอื่น

    use open qw( :encoding(UTF-8) :std );
  6. \N{CHARNAME}เปิดใช้งานตัวอักษรชื่อผ่านทาง

    use charnames qw( :full :short );
  7. หากคุณมีจุดDATAจับคุณต้องตั้งค่าการเข้ารหัสอย่างชัดเจน หากคุณต้องการให้เป็น UTF ‑ 8 ให้พูดว่า:

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

แน่นอนว่าไม่มีจุดจบของเรื่องอื่น ๆ ที่คุณอาจพบว่าตัวเองมีความกังวลในที่สุด แต่สิ่งเหล่านี้จะพอเพียงที่จะประมาณเป้าหมายของรัฐที่จะ“ ทำให้ทุกอย่างเพียงแค่ทำงานกับ UTF” 8” ถึงแม้ว่าจะค่อนข้างอ่อนไหวกับคำเหล่านั้น

อีกหนึ่ง pragma แม้ว่ามันจะไม่เกี่ยวข้องกับ Unicode ก็คือ:

      use autodie;

ขอแนะนำอย่างยิ่ง

🐪🐫🐪🌞🌴 𝕲𝖔𝕿𝖍𝖔𝖚𝖆𝖓𝖉𝕯𝖔𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞🐪🐫🐪🐁


🎁🐪𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊𝖋𝖔𝖗𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊𝕮𝖔𝖉𝖊🐪🎁


สำเร็จรูปของฉันเองวันนี้มีแนวโน้มที่จะมีลักษณะเช่นนี้:

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__

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


บอกว่า“ Perl ควร [ อย่างใด! ] เปิดใช้งาน Unicode โดยค่าเริ่มต้น” ยังไม่เริ่มคิดที่จะพูดให้มากพอที่จะมีประโยชน์เพียงเล็กน้อยในกรณีที่หายากและโดดเดี่ยว Unicode เป็นมากกว่าตัวละครที่มีขนาดใหญ่กว่ามาก มันเป็นสิ่งที่ตัวละครเหล่านั้นมีปฏิสัมพันธ์ในหลาย ๆ วิธี

แม้แต่มาตรการขั้นต่ำที่ง่าย ๆ ที่ผู้คน (บางคน) ดูเหมือนจะคิดว่าพวกเขาต้องการได้รับการรับประกันว่าจะทำลายรหัสบรรทัดนับล้าน ๆ รหัสที่ไม่มีโอกาสที่จะ "อัปเกรด" สู่ความทันสมัยBrave New World ใหม่ของคุณ

มันเป็นวิธีทางที่ซับซ้อนกว่าคนเสแสร้ง ฉันเคยคิดเกี่ยวกับเรื่องนี้มากทั้งในช่วงไม่กี่ปีที่ผ่านมา ฉันชอบที่จะแสดงให้เห็นว่าฉันผิด แต่ฉันไม่คิดว่าฉันเป็น Unicode นั้นซับซ้อนกว่าแบบจำลองที่คุณต้องการวางไว้บนพื้นและมีความซับซ้อนที่คุณไม่สามารถกวาดใต้พรมได้ หากคุณลองคุณจะผิดรหัสของคุณเองหรือของคนอื่น ในบางจุดคุณจะต้องพังและเรียนรู้ว่า Unicode เกี่ยวข้องกับอะไร คุณไม่สามารถทำเป็นว่ามันไม่ใช่สิ่งที่

🐪ออกนอกเส้นทางเพื่อทำให้ Unicode ง่ายกว่าสิ่งอื่นใดที่ฉันเคยใช้ หากคุณคิดว่าไม่ดีลองอย่างอื่นซักพัก จากนั้นกลับมาที่🐪: คุณจะได้กลับไปสู่โลกที่ดีกว่าหรือคุณจะนำความรู้แบบเดียวกันมากับคุณเพื่อที่เราจะได้ใช้ความรู้ใหม่ของคุณเพื่อทำให้สิ่งเหล่านี้ดีขึ้น


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


อย่างน้อยที่สุดนี่คือสิ่งที่ดูเหมือนจะจำเป็นสำหรับ🐪ถึง“ เปิดใช้งาน Unicode โดยค่าเริ่มต้น” ตามที่คุณกำหนดไว้:

  1. รหัสแหล่งที่มาทั้งหมดควรเป็น UTF-8 โดยค่าเริ่มต้น คุณจะได้รับด้วยหรือuse utf8export PERL5OPTS=-Mutf8

  2. ที่ DATAจับควรเป็น UTF-8 binmode(DATA, ":encoding(UTF-8)")คุณจะต้องทำเช่นนี้เป็นพื้นฐานต่อแพคเกจในขณะที่

  3. ข้อโต้แย้งของโปรแกรมสำหรับสคริปต์🐪ควรเข้าใจว่าเป็น UTF-8 โดยค่าเริ่มต้น export PERL_UNICODE=Aหรือหรือperl -CAexport PERL5OPTS=-CA

  4. อินพุตอินพุตเอาต์พุตและสตรีมข้อผิดพลาดมาตรฐานควรเป็นค่าเริ่มต้นเป็น UTF-8 export PERL_UNICODE=Sสำหรับพวกเขาทั้งหมดหรือI, Oและ / หรือEเพียงบางส่วนของพวกเขา เป็นเช่นperl -CSนี้

  5. ที่จับอื่น ๆ ที่เปิดโดย🐪ควรพิจารณา UTF-8 เว้นแต่จะมีการประกาศเป็นอย่างอื่น export PERL_UNICODE=Dหรือมีiและoสำหรับคนพิเศษเหล่านี้; export PERL5OPTS=-CDจะทำงาน. นั่นทำให้-CSADสำหรับพวกเขาทั้งหมด

  6. export PERL5OPTS=-Mopen=:utf8,:stdครอบคลุมทั้งฐานบวกทั้งหมดลำธารคุณเปิดด้วย ดูuniquote

  7. คุณไม่ต้องการพลาดข้อผิดพลาดในการเข้ารหัส UTF-8 ลองexport PERL5OPTS=-Mwarnings=FATAL,utf8ดู และให้แน่ใจว่ากระแสการป้อนข้อมูลของคุณมักจะbinmodeผ่านไปไม่ได้เพียงเพื่อ:encoding(UTF-8):utf8

  8. ควรเข้าใจจุดโค้ดระหว่าง 128–255 โดยให้🐪เป็นจุดรหัส Unicode ที่สอดคล้องกันไม่ใช่แค่ค่าไบนารีที่ไม่ผ่านการทดสอบ หรือuse feature "unicode_strings" export PERL5OPTS=-Mfeature=unicode_stringsที่จะทำให้และuc("\xDF") eq "SS" "\xE9" =~ /\w/ง่าย ๆexport PERL5OPTS=-Mv5.12หรือดีกว่าก็จะได้รับเช่นกัน

  9. อักขระ Unicode ที่ตั้งชื่อไม่ได้เปิดใช้งานตามค่าเริ่มต้นดังนั้นเพิ่มexport PERL5OPTS=-Mcharnames=:full,:short,latin,greekหรือบางส่วน ดูuninamesและtcgrep

  10. คุณต้องเข้าสู่ฟังก์ชั่นเกือบตลอดเวลาจากมาตรฐานUnicode::Normalizeโมดูลประเภทต่างๆของการสลายตัว export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKDแล้วเรียกใช้สิ่งที่เข้ามาผ่าน NFD และสิ่งขาออกจาก NFC เสมอ ไม่มีชั้น I / O เหล่านี้เป็นยังว่าฉันรู้ แต่ดูNFC , nfd , nfkdและnfkc

  11. การเปรียบเทียบสตริงใน🐪ใช้eq, ne, lc, cmp, sort& c & ซีซีมีความผิดเสมอ ดังนั้นแทนที่จะคุณจะต้อง@a = sort @b รวมทั้งอาจจะเพิ่มที่ของคุณ@a = Unicode::Collate->new->sort(@b) export PERL5OPTS=-MUnicode::Collateคุณสามารถแคชที่สำคัญสำหรับการเปรียบเทียบแบบไบนารี

  12. 🐪บิวด์อินprintfและwriteทำสิ่งผิดพลาดด้วยข้อมูล Unicode คุณจำเป็นต้องใช้โมดูลสำหรับอดีตและทั้งที่และยังโมดูลเป็นอย่างดีสำหรับหลัง ดูUWCและunifmtUnicode::GCStringUnicode::LineBreak

  13. หากคุณต้องการให้พวกเขานับเป็นจำนวนเต็มแล้วคุณจะให้มีการทำงานของคุณ\d+จับผ่านฟังก์ชั่นเพราะ🐪ของในตัวatoi (3) ปัจจุบันยังไม่ฉลาดพอUnicode::UCD::num

  14. คุณกำลังจะมีปัญหาเกี่ยวกับระบบไฟล์ในระบบไฟล์👽 ระบบไฟล์บางระบบบังคับใช้การแปลงเป็น NFC อย่างเงียบ ๆ อื่น ๆ บังคับใช้การแปลงเป็น NFD ในใจ และคนอื่นทำอย่างอื่นยังคง บางคนไม่สนใจเรื่องทั้งหมดซึ่งนำไปสู่ปัญหาที่ยิ่งใหญ่กว่า ดังนั้นคุณต้องจัดการ NFC / NFD ของคุณเองเพื่อรักษาสติ

  15. ทั้งหมดรหัสของคุณที่เกี่ยวข้องกับ🐪 a-zหรือA-Zและเช่นต้องมีการเปลี่ยนแปลงรวมทั้งm//, และs/// tr///มันควรจะโดดเด่นในฐานะธงแดงกรีดร้องที่รหัสของคุณเสีย แต่ยังไม่ชัดเจนว่าจะต้องเปลี่ยนแปลงอย่างไร การได้รับคุณสมบัติที่ถูกต้องและทำความเข้าใจกับเคสของพวกเขานั้นยากกว่าที่คุณคิด ฉันใช้unicharsและunipropsทุกวัน

  16. รหัสที่ใช้เกือบจะเป็นผิดเป็นรหัสที่ใช้\p{Lu} [A-Za-z]คุณต้องใช้\p{Upper}แทนและรู้เหตุผลว่าทำไม ใช่\p{Lowercase}และ\p{Lower}จะแตกต่างจากและ\p{Ll}\p{Lowercase_Letter}

  17. รหัสที่ใช้[a-zA-Z]ยิ่งแย่ลง และมันไม่สามารถใช้\pLหรือ\p{Letter}; \p{Alphabetic}จะต้องมีการใช้ ไม่ใช่ตัวอักษรทั้งหมดที่เป็นตัวอักษรคุณรู้!

  18. หากคุณกำลังมองหาตัวแปร with ด้วยแสดง/[\$\@\%]\w+/ว่าคุณมีปัญหา คุณต้องมองหา/[\$\@\%]\p{IDS}\p{IDC}*/และแม้แต่ที่ไม่ได้คิดเกี่ยวกับตัวแปรเครื่องหมายวรรคตอนหรือตัวแปรแพคเกจ

  19. หากคุณกำลังตรวจสอบช่องว่างคุณควรเลือกระหว่าง\hและ\vขึ้นอยู่กับ และคุณไม่ควรใช้\sเพราะมันไม่ได้หมายความว่า [\h\v]ขัดกับความเชื่อที่นิยม

  20. หากคุณกำลังใช้\nเส้นแบ่งเขตหรือแม้กระทั่งแสดง\r\nว่าคุณทำผิด คุณต้องใช้\Rซึ่งไม่เหมือนกัน!

  21. ถ้าคุณไม่รู้ว่าจะโทรUnicode :: Stringprep เมื่อไรและอย่างไรคุณก็จะได้เรียนรู้ที่ดีขึ้น

  22. การเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่จำเป็นต้องตรวจสอบว่ามีสองสิ่งที่เป็นตัวอักษรเดียวกัน วิธีที่ง่ายที่สุดในการทำเช่นนั้นคือด้วยโมดูลUnicode :: Collate Unicode::Collate->new(level => 1)->cmp($a, $b). นอกจากนี้ยังมีeqวิธีการและเช่นกันและคุณควรเรียนรู้เกี่ยวกับmatchและsubstrวิธีการเช่นกัน สิ่งเหล่านี้มีข้อได้เปรียบที่แตกต่างเหนือตัวเครื่องในตัว

  23. บางครั้งยังไม่เพียงพอและคุณต้องการUnicode :: Collate :: Locale module แทน Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)แทน พิจารณาว่าUnicode::Collate::->new(level => 1)->eq("d", "ð")เป็นเรื่องจริง แต่Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")เป็นเท็จ ในทำนองเดียวกัน "ae" และ "æ" คือeqถ้าคุณไม่ใช้ภาษาหรือถ้าคุณใช้ภาษาอังกฤษ แต่พวกเขาแตกต่างกันในภาษาไอซ์แลนด์ ตอนนี้คืออะไร ฉันบอกคุณแล้ว คุณสามารถเล่นกับ ucsortเพื่อทดสอบสิ่งเหล่านี้ได้

  24. พิจารณาวิธีจับคู่รูปแบบ CVCV (พยัญชนะสระสระพยัญชนะสระ) ในสตริง“ niño ” รูปแบบ NFD ของคุณ - ซึ่งคุณเคยสาปแช่งได้ดีกว่าได้จำไว้ว่าใส่ไว้ใน - กลายเป็น "nin \ x {303} o" ตอนนี้คุณจะทำอะไร แม้แต่ทำท่าว่าเสียงสระ[aeiou](ซึ่งผิดไป) คุณจะไม่สามารถทำอะไรอย่าง(?=[aeiou])\X)ใดอย่างหนึ่งเพราะแม้แต่ใน NFD รหัสจุดเช่น 'ø' ไม่สลายตัว ! อย่างไรก็ตามมันจะทดสอบเท่ากับ 'o' โดยใช้การเปรียบเทียบ UCA ที่ฉันเพิ่งแสดงให้คุณเห็น คุณไม่สามารถพึ่งพา NFD ได้คุณต้องพึ่งพา UCA


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


และนั่นไม่ใช่ทั้งหมด มีข้อสันนิษฐานหลายล้านข้อที่ผู้คนทำเกี่ยวกับ Unicode จนกว่าพวกเขาจะเข้าใจสิ่งเหล่านี้รหัสของพวกเขาจะถูกทำลาย

  1. รหัสที่ถือว่าสามารถเปิดไฟล์ข้อความโดยไม่ระบุการเข้ารหัสที่ใช้งานไม่ได้

  2. รหัสที่สมมติว่าการเข้ารหัสเริ่มต้นคือการเข้ารหัสของแพลตฟอร์มเนทีฟบางประเภทเกิดความเสียหาย

  3. รหัสที่สมมติว่าหน้าเว็บในญี่ปุ่นหรือจีนใช้พื้นที่น้อยกว่าใน UTF ‑ 16 มากกว่าใน UTF ‑ 8 ผิด

  4. รหัสที่ถือว่า Perl ใช้ UTF ‑ 8 ภายในนั้นผิด

  5. รหัสที่ถือว่าข้อผิดพลาดในการเข้ารหัสมักจะทำให้เกิดข้อยกเว้นขึ้นอยู่เสมอ

  6. รหัสที่ถือว่าเป็นจุดรหัส Perl จำกัด 0x10_FFFF ผิด

  7. รหัสที่สมมติว่าคุณสามารถตั้งค่า$/เป็นสิ่งที่จะทำงานกับตัวแยกบรรทัดที่ถูกต้องใด ๆ ที่ไม่ถูกต้อง

  8. รหัสที่สมมติว่ามีความเท่าเทียมกันของการปัดเศษบน casefolding อย่างเช่นlc(uc($s)) eq $sหรือuc(lc($s)) eq $sแตกหักและผิดทั้งหมด พิจารณาว่าuc("σ")และuc("ς") มีทั้ง"Σ"แต่lc("Σ")ไม่อาจกลับมาทั้งของคนเหล่านั้น

  9. รหัสที่ถือว่าทุกจุดรหัสตัวพิมพ์เล็กมีตัวพิมพ์ใหญ่หนึ่งตัวหรือในทางกลับกันจะใช้งานไม่ได้ ตัวอย่างเช่น"ª"เป็นตัวอักษรตัวพิมพ์เล็กที่ไม่มีตัวพิมพ์ใหญ่ ในขณะที่ทั้งสอง"ᵃ"และ"ᴬ"เป็นตัวอักษร แต่พวกเขาไม่ได้เป็นตัวอักษรตัวเล็ก; อย่างไรก็ตามทั้งคู่เป็นจุดรหัสตัวพิมพ์เล็กโดยไม่มีรุ่นตัวพิมพ์ใหญ่ที่สอดคล้องกัน ได้ไหม พวกเขาจะไม่ได้ \p{Lowercase_Letter}แม้จะเป็นทั้งสองและ\p{Letter}\p{Lowercase}

  10. รหัสที่สันนิษฐานว่าเปลี่ยนตัวพิมพ์ไม่ได้เปลี่ยนความยาวของสตริงที่ใช้งานไม่ได้

  11. รหัสที่สมมติว่ามีเพียงสองกรณีที่เสีย นอกจากนี้ยังมีชื่อเรื่อง

  12. รหัสที่ถือว่ามีเพียงตัวอักษรที่มีกรณีและปัญหา นอกเหนือจากตัวอักษรเพียงอย่างเดียวปรากฎว่าตัวเลขสัญลักษณ์และแม้แต่เครื่องหมายมีตัวอักษร ในความเป็นจริงการเปลี่ยนแปลงกรณีที่ยังสามารถทำให้บางสิ่งบางอย่างเปลี่ยนแปลงหมวดหมู่ทั่วไปหลักเช่นเปลี่ยนเป็น\p{Mark} \p{Letter}นอกจากนี้ยังสามารถทำให้สลับจากสคริปต์หนึ่งเป็นอีกสคริปต์หนึ่งได้

  13. รหัสที่ถือว่ากรณีนั้นไม่เคยขึ้นอยู่กับสถานที่เกิดเหตุเสียหาย

  14. รหัสที่สมมติว่า Unicode ให้รูปที่เกี่ยวกับ POSIX โลแคลเสียหาย

  15. รหัสที่สมมติว่าคุณสามารถลบเครื่องหมายกำกับออกเสียงเพื่อให้ได้ตัวอักษร ASCII พื้นฐานคือความชั่วร้าย, ยังคง, แตก, สมองเสียหาย, ผิดและเหตุผลในการลงโทษประหารชีวิต

  16. รหัสที่อนุมานว่าการออกเสียงกำกับ\p{Diacritic}และเครื่องหมาย\p{Mark}เป็นสิ่งเดียวกันเสีย

  17. รหัสที่ถือว่า\p{GC=Dash_Punctuation}ครอบคลุมมากที่สุดเท่าที่\p{Dash}จะถูกทำลาย

  18. รหัสที่ถือว่าเส้นประเครื่องหมายขีดคั่นและ minuses นั้นเป็นสิ่งเดียวกันกับรหัสอื่น ๆ หรือว่ามีเพียงหนึ่งรหัสเท่านั้นที่ถูกทำลายและผิด

  19. รหัสที่ถือว่าทุกจุดรหัสใช้เวลาไม่เกินหนึ่งคอลัมน์การพิมพ์เสีย

  20. รหัสที่สมมติว่า\p{Mark}อักขระทั้งหมดใช้คอลัมน์ศูนย์พิมพ์ไม่ได้

  21. รหัสที่สันนิษฐานว่าตัวละครที่ดูเหมือนกันอยู่เหมือนกันเสีย

  22. รหัสที่สมมติว่าตัวละครที่ไม่เหมือนกันจะไม่แตกหัก

  23. รหัสที่สมมติว่ามีการ จำกัด จำนวนคะแนนในแถวที่มีเพียงอันเดียวที่\Xสามารถจับคู่ได้ผิด

  24. รหัสที่สมมติว่า\Xไม่สามารถเริ่มต้นด้วย\p{Mark}ตัวละครนั้นผิด

  25. รหัสที่สมมติว่า\Xไม่สามารถมี\p{Mark}ตัวละครที่ไม่ใช่สองตัวถือเป็นความผิด

  26. รหัสที่สมมติว่าไม่สามารถใช้งาน"\x{FFFF}"ผิดได้

  27. รหัสที่ถือว่าเป็นจุดรหัสที่ไม่ใช่ BMP ที่ต้องการหน่วยรหัส UTF-16 (ตัวแทน) สองชุดจะเข้ารหัสเป็นอักขระ UTF-8 สองตัวแยกกันหนึ่งตัวต่อหน่วยรหัสผิด มันไม่ได้: มันเข้ารหัสไปยังจุดรหัสเดียว

  28. รหัสที่แปลงจาก UTF ‐ 16 หรือ UTF ‐ 32 ที่มี BOM ชั้นนำไปเป็น UTF ‐ 8 จะแตกถ้ามันวาง BOM ไว้ที่จุดเริ่มต้นของผลลัพธ์ UTF-8 นี่ช่างโง่เหลือเกินที่ควรเอาหนังตาออก

  29. รหัสที่ถือว่า CESU-8 เป็นการเข้ารหัส UTF ที่ถูกต้องนั้นผิด โค้ดที่คิดว่าการเข้ารหัส U + 0000 เช่นเดียวกับ"\xC0\x80"UTF-8 นั้นแตกและผิด พวกเหล่านี้สมควรได้รับการรักษาเปลือกตา

  30. รหัสที่สมมติว่าตัวละครเช่น>ชี้ไปทางขวา<เสมอและชี้ไปทางซ้ายเสมอไม่ถูกต้อง - เพราะในความเป็นจริงไม่ได้

  31. รหัสที่สมมติว่าถ้าคุณส่งออกตัวแรกXและจากนั้นตัวละครYที่จะปรากฏขึ้นว่าXYเป็นความผิด บางครั้งพวกเขาทำไม่ได้

  32. รหัสที่สมมติว่า ASCII นั้นดีพอสำหรับการเขียนภาษาอังกฤษอย่างถูกต้องคือโง่สั้นสายตาสั้นไม่รู้หนังสือชั่วร้ายและผิด ออกไปด้วยหัวของพวกเขา! หากดูเหมือนว่ารุนแรงเกินไปเราสามารถประนีประนอมต่อจากนี้ไปพวกเขาอาจพิมพ์ด้วยนิ้วเท้าใหญ่จากเท้าข้างเดียว (ส่วนที่เหลือจะติดเทปกาว)

  33. รหัสที่สมมติว่า\p{Math}จุดรหัสทั้งหมดเป็นอักขระที่มองเห็นได้ผิด

  34. รหัสที่\wมีเพียงตัวอักษรตัวเลขและขีดล่างนั้นเป็นรหัสที่ผิด

  35. รหัสที่สันนิษฐานว่า^และ~เป็นเครื่องหมายวรรคตอนไม่ถูกต้อง

  36. รหัสที่สมมติว่าüมีเครื่องหมายบนอากาศผิด

  37. รหัสที่เชื่อว่าสิ่งต่าง ๆ เช่นมีตัวอักษรใด ๆ ในพวกเขาเป็นสิ่งที่ผิด

  38. รหัสที่เชื่อว่า\p{InLatin}เป็นเช่นเดียวกับที่\p{Latin}ถูกทำลายอย่างมากมาย

  39. รหัสที่เชื่อว่า\p{InLatin}มีประโยชน์เกือบจะไม่ถูกต้องแน่นอน

  40. รหัสที่เชื่อว่าให้$FIRST_LETTERเป็นตัวอักษรตัวแรกในตัวอักษรบางตัวและ$LAST_LETTERเป็นตัวอักษรตัวสุดท้ายในตัวอักษรเดียวกันนั้นที่[${FIRST_LETTER}-${LAST_LETTER}]มีความหมายใด ๆ ก็ตามที่เกือบจะสมบูรณ์เสียและผิดและไร้ความหมาย

  41. รหัสที่เชื่อว่าชื่อของใครบางคนสามารถมีได้เฉพาะอักขระบางตัวเท่านั้นคือโง่เขลาและผิด

  42. รหัสที่พยายามลด Unicode ให้เป็น ASCII นั้นไม่เพียง แต่ผิดผู้กระทำการไม่ควรได้รับอนุญาตให้ทำงานในการเขียนโปรแกรมอีกครั้ง ระยะเวลา ฉันไม่ได้เป็นบวกพวกเขาควรได้รับอนุญาตให้ดูอีกครั้งเพราะเห็นได้ชัดว่าไม่ได้ทำให้พวกเขาเก่งมากจนถึงตอนนี้

  43. รหัสที่เชื่อว่ามีวิธีการเข้ารหัสไฟล์ข้อความที่ทำท่าว่าไม่มีอยู่เสียและอันตราย อาจโผล่ตาอีกข้างด้วยเช่นกัน

  44. รหัสที่แปลงอักขระที่ไม่รู้จัก?เป็นแบบเสีย, โง่, braindead และทำงานตรงกันข้ามกับคำแนะนำมาตรฐานซึ่งบอกว่าจะไม่ทำเช่นนั้น! RTFM เพราะเหตุใด

  45. รหัสที่เชื่อว่าสามารถคาดเดาได้อย่างน่าเชื่อถือว่าการเข้ารหัสไฟล์ข้อความที่ไม่ได้ทำเครื่องหมายนั้นเป็นความผิดของการรวมตัวกันของความโอหังและnaïvetéที่สายฟ้าสายฟ้าจาก Zeus เท่านั้นที่จะแก้ไขได้

  46. รหัสที่เชื่อว่าคุณสามารถใช้printfความกว้างของ to ในการ pad และปรับข้อมูล Unicode ให้เสียหายและไม่ถูกต้อง

  47. รหัสที่เชื่อว่าเมื่อคุณสร้างไฟล์ด้วยชื่อที่กำหนดสำเร็จเมื่อคุณเรียกใช้lsหรือreaddirในไดเรกทอรีที่มีการปิดล้อมคุณจะพบว่าไฟล์ที่มีชื่อที่คุณสร้างไว้นั้นเป็นไฟล์บั๊กแตกและผิด หยุดประหลาดใจกับสิ่งนี้!

  48. รหัสที่เชื่อว่า UTF-16 คือการเข้ารหัสความกว้างคงที่คือโง่หักและผิด เพิกถอนใบอนุญาตการเขียนโปรแกรมของพวกเขา

  49. รหัสที่ปฏิบัติกับจุดรหัสจากระนาบหนึ่งอันที่แตกต่างจากระนาบอื่นคือipso factoเสียและผิด กลับไปโรงเรียน

  50. รหัสที่เชื่อว่าสิ่งต่าง ๆ เช่น/s/iสามารถจับคู่"S"หรือ"s"เสียและผิด คุณจะประหลาดใจ

  51. รหัสที่ใช้\PM\pM*ในการค้นหากลุ่มภาพกราฟิกแทนการใช้\Xนั้นใช้งานไม่ได้และผิด

  52. คนที่ต้องการที่จะกลับไปโลก ASCII ที่ควรจะเป็นทั้งใจกำลังใจที่จะทำเช่นนั้นและในเกียรติของการอัพเกรดรุ่งโรจน์ของพวกเขาควรจะให้ฟรีด้วยเครื่องพิมพ์ดีดไฟฟ้าไว้ล่วงหน้าสำหรับทุกความต้องการของพวกเขาในการป้อนข้อมูล ข้อความที่ส่งถึงพวกเขาควรจะส่งผ่านทางโทรเลข at ที่ 40 ตัวอักษรต่อบรรทัดและส่งโดยผู้ให้บริการจัดส่ง หยุด.


😱𝕾𝖀𝕸𝕸𝕬𝕽𝖄😱


ฉันไม่รู้ว่า“ Unicode เริ่มต้นใน🐪” คุณจะได้รับอะไรมากกว่าที่ฉันเขียน ใช่ฉัน: คุณควรจะใช้Unicode::CollateและUnicode::LineBreakเช่นกัน และอาจมากกว่า

ในขณะที่คุณดูมีสิ่ง Unicode ไกลมากเกินไปว่าคุณไม่ต้องกังวลกับการให้มีเท่าที่เคยมีอยู่สิ่งใด ๆ ดังกล่าวว่า“เริ่มต้นเป็น Unicode”

สิ่งที่คุณจะค้นพบเช่นเดียวกับที่เราได้ทำกลับมาใน, 5.8 ว่าเป็นไปไม่ได้เลยที่จะกำหนดสิ่งเหล่านี้ทั้งหมดในรหัสที่ไม่ได้รับการออกแบบตั้งแต่ต้นจนถึงบัญชีสำหรับพวกเขา ความเห็นแก่ตัวที่มีความหมายดีของคุณทำลายทั้งโลก

และแม้กระทั่งเมื่อคุณทำยังมีปัญหาที่สำคัญที่ต้องใช้ความคิดจำนวนมากเพื่อให้ถูกต้อง ไม่มีสวิตช์ที่คุณสามารถพลิกได้ ไม่มีอะไรนอกจากสมองและฉันหมายถึงสมองที่แท้จริงจะพอเพียงที่นี่ มีสิ่งมากมายที่คุณต้องเรียนรู้ โมดูล่าถอยกลับไปที่เครื่องพิมพ์ดีดด้วยตนเองคุณก็ไม่สามารถหวังที่จะแอบโดยไม่รู้ นี่คือศตวรรษที่ 21 และคุณไม่ต้องการให้ Unicode หายไปโดยไม่รู้ตัว

คุณต้องเรียนรู้มัน ระยะเวลา มันจะไม่ง่ายเลยที่“ ทุกอย่างจะได้ผล” เพราะนั่นจะรับประกันได้ว่าสิ่งต่าง ๆไม่ทำงาน - ซึ่งทำให้สมมติฐานสันนิษฐานว่าเป็นโมฆะในการ“ ทำให้ทุกอย่างทำงาน”

คุณอาจสามารถรับค่าเริ่มต้นที่สมเหตุสมผลสำหรับการดำเนินการที่ จำกัด และไม่มาก แต่ไม่ได้โดยไม่ต้องคิดอะไรมากไปกว่าที่ฉันคิดไว้

เช่นเดียวกับตัวอย่างการสั่งแบบบัญญัติจะทำให้ปวดหัวจริงบางอย่าง 😭 "\x{F5}" 'õ' , "o\x{303}" 'õ' , "o\x{303}\x{304}" 'ȭ'และ"o\x{304}\x{303}" 'ō̃'ควรตรงกับ'õ'แต่คุณจะทำเช่นไรในโลกนี้ สิ่งนี้ยากกว่าที่คิด แต่มันเป็นสิ่งที่คุณต้องคำนึงถึง 💣

หากมีสิ่งหนึ่งที่ผมรู้เกี่ยวกับ Perl, มันคืออะไรบิต Unicode มันทำและไม่ทำและสิ่งนี้ผมสัญญาว่าคุณ: “ᴛʜᴇʀᴇɪsɴᴏUɴɪᴄᴏᴅᴇᴍᴀɢɪᴄʙᴜʟʟᴇᴛ” 😞

คุณไม่สามารถเปลี่ยนค่าเริ่มต้นและรับการแล่นเรืออย่างราบรื่น มันเป็นความจริงที่ฉันรัน🐪ด้วยการPERL_UNICODEตั้งค่าให้"SA"แต่นั่นคือทั้งหมด สำหรับการทำงานจริงฉันทำตามทุกขั้นตอนที่ระบุไว้ข้างต้นและฉันทำมันอย่างระมัดระวังมาก


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


56
เช่นเดียวกับ Sherm Pendley ชี้: "ทั้งหมด!" ถ้าฉันเขียนสิ่งใหม่วันนี้ UTF-8 น่าจะเป็นวิธีที่ง่ายที่สุดที่จะทำให้เสร็จ มันไม่ใช่. สำเร็จรูปของคุณ prooves ไม่ใช่ทุกคนที่มีความรู้เช่นนั้นที่จะเปลี่ยนแก้วน้ำให้อยู่ในตำแหน่งที่เหมาะสม ฉันขอโทษฉันมีวันที่ยาวนานและยากลำบากดังนั้นฉันจะแสดงความคิดเห็นในรายการหลักในวันพรุ่งนี้พร้อมตัวอย่าง
สัปดาห์

17
ข้อสรุปหนึ่งควรชัดเจนจากการอ่านรายการข้างต้น: ไม่ต้องคำนึงถึงตัวพิมพ์ใหญ่ - เล็ก ทำไม่ได้ เคย คอมพิวเตอร์ที่มีราคาแพงและมีความหมายซึ่งขึ้นอยู่กับสิ่งที่สำคัญมากคือ "สถานที่" พยายามที่จะระบุไม่สำเร็จ
Tim Bray

72
ฉันเป็นคนเดียวที่พบว่าแดกดันที่โพสต์นี้แสดงให้เห็นว่า tchrist แตกต่างกันอย่างมากใน FF / Chrome / IE / Opera บางครั้งจนถึงจุดที่อ่านไม่ออก?
damageboy

15
ในขณะที่ฉันชอบโพสต์โดยทั่วไปและทำ upvote สิ่งหนึ่งที่ทำให้นรกออกจากตัวฉัน มี "รหัสที่ ... ใช้ไม่ได้" จำนวนมาก แม้ว่าฉันจะไม่โต้เถียงกับแถลงการณ์ แต่ฉันคิดว่ามันเป็นการดีที่จะแสดงความแตกแยก ด้วยวิธีนี้มันจะข้าม (คำตอบส่วนนี้) จากการคุยโวเพื่อการศึกษา

36
@xenoterracide ไม่ฉันไม่ได้ใช้จุดรหัสที่เป็นปัญหา มันเป็นโครงเรื่องที่จะให้คุณติดตั้งฟอนต์ Symbola ที่ยอดเยี่ยมของ George Dourosซึ่งครอบคลุม Unicode 6.0 😈 @depesz ไม่มีห้องพักที่นี่ที่จะอธิบายว่าทำไมการโจมตีแต่ละครั้งที่ผิดพลาดนั้นไม่ถูกต้อง @leonbloy จำนวนมากและสิ่งนี้มีผลกับ Unicode โดยทั่วไปไม่ใช่แค่ Perl เนื้อหาบางส่วนนี้อาจปรากฏใน“ การเขียนโปรแกรม Perl 🐪, ฉบับที่ 4 , จะครบกำหนดในเดือนตุลาคม 🎃ฉันเหลือเวลาอีกหนึ่งเดือนในการทำงานกับมันและUnicode นั้นอยู่ที่นั่น regexes เช่นกัน
tchrist

96

มีสองขั้นตอนในการประมวลผลข้อความ Unicode ที่แรกก็คือ "ฉันจะป้อนและส่งออกโดยไม่สูญเสียข้อมูล" ประการที่สองคือ "ฉันจะปฏิบัติต่อข้อความตามแบบแผนภาษาท้องถิ่นได้อย่างไร"

โพสต์ของ tchrist ครอบคลุมทั้งสอง แต่ส่วนที่สองคือตำแหน่งที่ 99% ของข้อความในโพสต์ของเขามาจาก โปรแกรมส่วนใหญ่ไม่ได้จัดการ I / O อย่างถูกต้องดังนั้นจึงเป็นสิ่งสำคัญที่จะต้องเข้าใจก่อนที่คุณจะเริ่มกังวลเกี่ยวกับการทำให้ปกติและการเรียงหน้า

โพสต์นี้มีวัตถุประสงค์เพื่อแก้ไขปัญหาแรก

เมื่อคุณอ่านข้อมูลไปยัง Perl มันไม่สนใจว่าจะเข้ารหัสอะไร มันจัดสรรหน่วยความจำบางส่วนและหยุดไบต์ที่นั่น ถ้าคุณบอกว่าprint $strมันแค่แบ่งไบต์เหล่านั้นออกไปยังเทอร์มินัลของคุณซึ่งอาจถูกตั้งค่าให้ถือว่าทุกอย่างที่เขียนไว้คือ UTF-8 และข้อความของคุณจะปรากฏขึ้น

มหัศจรรย์

ยกเว้นมันไม่ใช่ หากคุณพยายามรักษาข้อมูลเป็นข้อความคุณจะเห็นว่ามีบางสิ่งไม่ดีเกิดขึ้น คุณไม่จำเป็นต้องไปไกลกว่านี้lengthเพื่อดูว่า Perl คิดอย่างไรกับสตริงของคุณและสิ่งที่คุณคิดเกี่ยวกับสตริงไม่เห็นด้วย เขียนสิ่งที่คล้ายกัน: perl -E 'while(<>){ chomp; say length }'และพิมพ์文字化けและคุณจะได้ 12 ... ไม่ใช่คำตอบที่ถูกต้อง 4

นั่นเป็นเพราะ Perl ถือว่าสตริงของคุณไม่ใช่ข้อความ คุณต้องบอกว่ามันเป็นข้อความก่อนที่มันจะให้คำตอบที่ถูกต้อง

ง่ายพอ โมดูล Encode มีฟังก์ชันที่จะทำเช่นนั้น จุดเข้าใช้งานทั่วไปคือEncode::decode(หรือuse Encode qw(decode)แน่นอน) ฟังก์ชั่นนั้นใช้สตริงบางส่วนจากโลกภายนอก (สิ่งที่เราจะเรียกว่า "octets" วิธีแฟนซีของการพูดว่า "8-bit bytes") และเปลี่ยนเป็นข้อความที่ Perl จะเข้าใจ อาร์กิวเมนต์แรกคือชื่อการเข้ารหัสอักขระเช่น "UTF-8" หรือ "ASCII" หรือ "EUC-JP" อาร์กิวเมนต์ที่สองคือสตริง ค่าส่งคืนคือสเกลาร์ Perl ที่มีข้อความ

(นอกจากนี้ยังมีEncode::decode_utf8ซึ่งสันนิษฐานว่าเป็น UTF-8 สำหรับการเข้ารหัส)

หากเราเขียนหนึ่งซับของเราใหม่:

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

เราพิมพ์文字化けและรับ "4" เป็นผลลัพธ์ ความสำเร็จ

นั่นตรงนั้นเป็นวิธีแก้ปัญหา 99% ของปัญหา Unicode ใน Perl

ที่สำคัญคือเมื่อใดก็ตามที่ข้อความเข้ามาในโปรแกรมของคุณคุณจะต้องถอดรหัส อินเทอร์เน็ตไม่สามารถส่งอักขระได้ ไฟล์ไม่สามารถเก็บอักขระได้ ไม่มีตัวละครในฐานข้อมูลของคุณ มีออคเต็ตเท่านั้นและคุณไม่สามารถถือว่าอ็อคเท็ตเป็นตัวละครใน Perl คุณต้องถอดรหัสอ็อกเท็ตที่เข้ารหัสเป็นอักขระ Perl ด้วยโมดูลการเข้ารหัส

อีกครึ่งหนึ่งของปัญหาคือการนำข้อมูลออกจากโปรแกรมของคุณ นั่นเป็นเรื่องง่าย คุณเพียงแค่บอกว่าuse Encode qw(encode)ตัดสินใจว่าการเข้ารหัสข้อมูลของคุณจะอยู่ใน (UTF-8 กับขั้วที่เข้าใจ UTF-8, UTF-16 สำหรับไฟล์บน Windows, ฯลฯ ) และแล้วออกผลมาจากการencode($encoding, $data)แทนเพียง $dataoutputting

การดำเนินการนี้จะแปลงอักขระของ Perl ซึ่งเป็นสิ่งที่โปรแกรมของคุณทำงานไปสู่อ็อกเท็ตที่สามารถใช้งานได้โดยโลกภายนอก มันจะง่ายกว่านี้มากถ้าเราสามารถส่งตัวละครผ่านทางอินเทอร์เน็ตหรือไปยังเครื่องเทอร์มินัลของเรา แต่เราทำไม่ได้: octets เท่านั้น ดังนั้นเราต้องแปลงอักขระเป็นอ็อกเท็ตมิฉะนั้นผลลัพธ์จะไม่ถูกกำหนด

ในการสรุป: เข้ารหัสเอาต์พุตทั้งหมดและถอดรหัสอินพุตทั้งหมด

ตอนนี้เราจะพูดถึงสามประเด็นที่ทำให้สิ่งนี้ท้าทายเล็กน้อย ที่แรกก็คือห้องสมุด พวกเขาจัดการข้อความอย่างถูกต้องหรือไม่ คำตอบคือ ... พวกเขาลอง หากคุณดาวน์โหลดเว็บเพจ LWP จะให้ผลลัพธ์เป็นข้อความ หากคุณเรียกใช้วิธีการที่ถูกต้องกับผลลัพธ์นั่นคือ (และสิ่งนั้นเกิดขึ้นdecoded_contentไม่ใช่contentซึ่งเป็นเพียงสตรีมออคเต็ตที่ได้มาจากเซิร์ฟเวอร์) ไดรเวอร์ฐานข้อมูลอาจไม่สม่ำเสมอ ถ้าคุณใช้ DBD :: SQLite ด้วย Perl เพียงอย่างเดียวมันจะได้ผล แต่ถ้ามีเครื่องมืออื่น ๆ ที่ใส่ข้อความที่เก็บไว้เป็นการเข้ารหัสแบบอื่นที่ไม่ใช่ UTF-8 ในฐานข้อมูลของคุณ ... ดี ... มันจะไม่ถูกจัดการอย่างถูกต้อง จนกว่าคุณจะเขียนโค้ดเพื่อจัดการอย่างถูกต้อง

ข้อมูลที่ส่งออกนั้นมักจะง่ายกว่า แต่ถ้าคุณเห็น "ตัวอักษรขนาดใหญ่ในการพิมพ์" คุณจะรู้ว่าคุณกำลังสับสนการเข้ารหัสอยู่ที่ไหนสักแห่ง คำเตือนนั้นหมายความว่า "เฮ้คุณกำลังพยายามรั่วไหลตัวละคร Perl ไปยังโลกภายนอกและนั่นก็ไม่สมเหตุสมผล" โปรแกรมของคุณดูเหมือนจะทำงานได้ (เพราะส่วนอื่น ๆ มักจะจัดการกับตัวอักขระ Perl ที่ถูกต้อง) แต่มันก็หักและสามารถหยุดทำงานได้ทุกเมื่อ แก้ไขด้วยความชัดเจนEncode::encode!

ปัญหาที่สองคือซอร์สโค้ดที่เข้ารหัส UTF-8 เว้นแต่คุณจะพูดuse utf8ที่ด้านบนของแต่ละไฟล์ Perl จะไม่คิดว่าซอร์สโค้ดของคุณคือ UTF-8 ซึ่งหมายความว่าทุกครั้งที่คุณพูดอะไรบางอย่างmy $var = 'ほげ'คุณกำลังฉีดขยะเข้าไปในโปรแกรมซึ่งจะทำให้ทุกอย่างพังทลายอย่างสิ้นเชิง คุณไม่จำเป็นต้อง "ใช้ utf8" แต่ถ้าไม่คุณต้องไม่ใช้อักขระที่ไม่ใช่ ASCII ในโปรแกรมของคุณ

ปัญหาที่สามคือวิธีที่ Perl จัดการกับอดีต นานมาแล้วไม่มีสิ่งเช่น Unicode และ Perl คิดว่าทุกอย่างเป็นข้อความละตินหรือไบนารี ดังนั้นเมื่อข้อมูลเข้าสู่โปรแกรมของคุณและคุณเริ่มใช้มันเป็นข้อความ Perl จะถือว่าแต่ละ octet เป็นตัวอักษรละติน -1 นั่นเป็นเหตุผลที่เมื่อเราถามถึงความยาวของ "文字化け" เราได้ 12 Perl คิดว่าเรากำลังดำเนินการในสตริงละติน -1 "æååã" (ซึ่งคือ 12 ตัวอักษรบางส่วนที่ไม่ได้พิมพ์)

สิ่งนี้เรียกว่า "การอัพเกรดโดยนัย" และเป็นสิ่งที่สมเหตุสมผลอย่างสมบูรณ์แบบ แต่ไม่ใช่สิ่งที่คุณต้องการหากข้อความของคุณไม่ใช่ภาษาละติน -1 นั่นเป็นเหตุผลที่สำคัญที่จะต้องถอดรหัสอินพุตอย่างชัดเจน: หากคุณไม่ทำมัน Perl จะและอาจทำผิด

ผู้คนมีปัญหาในการที่ข้อมูลครึ่งหนึ่งของพวกเขาเป็นสตริงอักขระที่เหมาะสมและบางส่วนยังคงเป็นไบนารี Perl จะตีความส่วนที่ยังคงเป็นเลขฐานสองราวกับว่าเป็นข้อความแบบละติน -1 แล้วรวมเข้ากับข้อมูลอักขระที่ถูกต้อง สิ่งนี้จะทำให้ดูเหมือนว่าการจัดการตัวละครของคุณถูกทำลายโปรแกรมของคุณอย่างถูกต้อง แต่ในความเป็นจริงคุณไม่ได้แก้ไขให้เพียงพอ

ต่อไปนี้เป็นตัวอย่าง: คุณมีโปรแกรมที่อ่านไฟล์ข้อความที่เข้ารหัส UTF-8 คุณจะจับ Unicode PILE OF POOไปยังแต่ละบรรทัดแล้วพิมพ์ออกมา คุณเขียนมันชอบ:

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

จากนั้นเรียกใช้ข้อมูลที่เข้ารหัส UTF-8 เช่น:

perl poo.pl input-data.txt

มันพิมพ์ข้อมูล UTF-8 ด้วย poo ที่ส่วนท้ายของแต่ละบรรทัด สมบูรณ์แบบโปรแกรมของฉันทำงาน!

แต่ไม่คุณกำลังทำการต่อข้อมูลไบนารี่ คุณกำลังอ่าน octets จากไฟล์ที่ลบ\nกับ chomp แล้วตรึงบนไบต์ใน UTF-8 เป็นตัวแทนของPILE OF POOตัวละคร เมื่อคุณแก้ไขโปรแกรมของคุณเพื่อถอดรหัสข้อมูลจากไฟล์และเข้ารหัสผลลัพธ์คุณจะสังเกตเห็นว่าคุณได้รับขยะ ("ð©") แทนที่จะเป็น poo สิ่งนี้จะทำให้คุณเชื่อว่าการถอดรหัสไฟล์อินพุตเป็นสิ่งที่ผิดที่ต้องทำ มันไม่ใช่.

ปัญหาคือว่า poo กำลังถูกอัพเกรดโดยนัยเป็น latin-1 ถ้าคุณuse utf8สร้างข้อความตามตัวอักษรแทนที่จะเป็นไบนารี่มันจะกลับมาทำงานอีกครั้ง!

(นั่นคือปัญหาอันดับหนึ่งที่ฉันเห็นเมื่อช่วยเหลือผู้คนที่มี Unicode พวกเขาทำในสิ่งที่ถูกต้องและทำลายโปรแกรมของพวกเขานั่นคือสิ่งที่น่าเศร้าเกี่ยวกับผลลัพธ์ที่ไม่ได้กำหนด: คุณสามารถมีโปรแกรมทำงานเป็นเวลานาน แต่เมื่อคุณเริ่มซ่อม มันหยุดไม่ต้องกังวลหากคุณเพิ่มคำสั่ง encode / decode ลงในโปรแกรมของคุณและหยุดพักมันก็หมายความว่าคุณมีงานที่ต้องทำอีกมากในครั้งต่อไปเมื่อคุณออกแบบด้วย Unicode ในใจตั้งแต่ต้นมันจะเป็น ง่ายกว่ามาก!)

นั่นคือทั้งหมดที่คุณต้องรู้เกี่ยวกับ Perl และ Unicode ถ้าคุณบอก Perl ว่าข้อมูลของคุณคืออะไรมันมีการสนับสนุน Unicode ที่ดีที่สุดในบรรดาภาษาโปรแกรมยอดนิยมทั้งหมด หากคุณสมมติว่ามันจะรู้ได้อย่างน่าอัศจรรย์ว่าข้อความประเภทใดที่คุณป้อนอยู่นั้นคุณจะทิ้งข้อมูลของคุณอย่างถาวร เพียงเพราะโปรแกรมของคุณทำงานในวันนี้ที่เทอร์มินัล UTF-8 ของคุณไม่ได้หมายความว่ามันจะทำงานในวันพรุ่งนี้ในไฟล์ที่เข้ารหัส UTF-16 ดังนั้นให้ปลอดภัยในตอนนี้และช่วยตัวคุณเองด้วยการกำจัดข้อมูลผู้ใช้ของคุณ!

ส่วนที่ง่ายของการจัดการ Unicode คือการเข้ารหัสเอาต์พุตและการถอดรหัสอินพุต ส่วนที่ยากคือการค้นหาอินพุตและเอาต์พุตทั้งหมดของคุณและพิจารณาว่าการเข้ารหัสนั้นคืออะไร แต่นั่นเป็นเหตุผลว่าทำไมคุณถึงได้เหรียญใหญ่ :)


หลักการอธิบายได้ดี แต่วิธีการปฏิบัติสำหรับ I / O หายไป การใช้Encodeโมดูลอย่างชัดเจนน่าเบื่อและเกิดข้อผิดพลาดและทำให้การอ่านโค้ดที่เกี่ยวข้องกับ I / O นั้นเจ็บปวดจริงๆ ชั้น I / O จัดเตรียมโซลูชันตามที่พวกเขาเข้ารหัสโปร่งใสและถอดรหัสหากจำเป็น openและbinmodeอนุญาตให้มีการกำหนดและ pragma openตั้งค่าเริ่มต้นตามที่ tchrist แนะนำในคำตอบของเขา
Palec

48

เราทุกคนต่างเห็นพ้องกันว่ามันเป็นปัญหาที่ยากด้วยเหตุผลหลายประการ แต่นั่นเป็นเหตุผลที่แม่นยำในการพยายามทำให้ทุกคนง่ายขึ้น

มีโมดูลล่าสุดใน CPAN, utf8 :: all , ที่พยายามที่จะ "เปิด Unicode. ทั้งหมดของมัน"

ตามที่ได้กล่าวไว้คุณไม่สามารถทำให้ทั้งระบบ (โปรแกรมภายนอกการร้องขอจากเว็บภายนอก ฯลฯ ) ได้อย่างน่าอัศจรรย์ใช้ Unicode ด้วยเช่นกัน แต่เราสามารถทำงานร่วมกันเพื่อสร้างเครื่องมือที่สมเหตุสมผลที่ทำให้การทำปัญหาทั่วไปง่ายขึ้น นั่นคือเหตุผลที่เราเป็นโปรแกรมเมอร์

ถ้า utf8 :: ทั้งหมดไม่ได้ทำสิ่งที่คุณคิดว่ามันควรจะปรับปรุงให้ดีขึ้น หรือทำเครื่องมือเพิ่มเติมที่รวมกันสามารถตอบสนองความต้องการที่แตกต่างกันของผู้คนให้มากที่สุด

`


5
ฉันเห็นพื้นที่มากมายสำหรับการปรับปรุงในutf8::allโมดูลที่อ้างถึง มันถูกเขียนขึ้นก่อนที่unicode_stringsฟีเจอร์ซึ่งFᴛᴀɴᴅᴀᴛLᴏɴɢLᴀsᴛจะแก้ไข regexes เพื่อให้/uพวกเขา ฉันไม่เชื่อว่าจะทำให้เกิดข้อยกเว้นในการเข้ารหัสข้อผิดพลาดและนั่นคือสิ่งที่คุณต้องมีอย่างแท้จริง มันไม่โหลดในuse charnames ":full"pragma ซึ่งยังไม่โหลดอัตโนมัติ มันไม่ได้เตือน[a-z]และเช่นprintfความกว้างของสตริงการใช้\nแทน\Rและ.แทนที่จะเป็น\Xแต่อาจจะเป็นPerl::Criticเรื่องมากกว่านั้น หากเป็นฉันฉันจะเพิ่ม𝐍𝐅𝐃เข้าและออก.
tchrist

13
@tchrist ปัญหาการติดตามสำหรับ utf8 :: ทั้งหมดอยู่ที่นี่ github.com/doherty/utf8-all/issues พวกเขาชอบที่จะได้ยินคำแนะนำของคุณ
Schwern

4
@Schwern: buts แต่รู้สึกอิสระที่จะขโมยและหยิกจากสิ่งที่ฉันได้เขียนที่นี่ ความซื่อสัตย์ฉันยังคงรู้สึก / เรียนรู้สิ่งที่สามารถทำได้กับสิ่งที่ควรทำและที่ไหน นี่เป็นตัวอย่างที่ดีออก offloading unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -rการเรียงลำดับ: ในทำนองเดียวกันขั้นตอนการเตรียมล่วงหน้าเล็ก ๆ น้อย ๆ เช่น... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'นั้นก็ทำได้ดีเช่นกันและฉันไม่ต้องการตัดสินใจของคนอื่น ฉันยังคงสร้างกล่อง Unicode ของฉัน
tchrist

35

ฉันคิดว่าคุณเข้าใจผิด Unicode และความสัมพันธ์กับ Perl ไม่ว่าคุณจะเก็บข้อมูลแบบใด Unicode ISO-8859-1หรืออื่น ๆ อีกมากมายโปรแกรมของคุณต้องรู้วิธีตีความไบต์ที่ได้รับเป็นอินพุต (ถอดรหัส) และวิธีแสดงข้อมูลที่ต้องการแสดงผล (เข้ารหัส) ) ทำให้การตีความผิดพลาดและคุณบิดเบือนข้อมูล ไม่มีการตั้งค่าเริ่มต้นที่วิเศษในโปรแกรมของคุณที่จะบอกสิ่งที่อยู่นอกโปรแกรมของคุณว่าจะทำอย่างไร

คุณคิดว่ามันเป็นไปได้ยากเพราะคุณคุ้นเคยกับทุกสิ่งที่เป็น ASCII ทุกสิ่งที่คุณควรคำนึงถึงคือการไม่สนใจภาษาการเขียนโปรแกรมและทุกสิ่งที่มันต้องโต้ตอบด้วย หากทุกอย่างไม่ได้ใช้อะไรนอกจาก UTF-8 และคุณไม่มีทางเลือก UTF-8 ก็จะง่ายเหมือนกัน แต่ไม่ใช่ทุกอย่างที่ใช้ UTF-8 ตัวอย่างเช่นคุณไม่ต้องการให้ตัวจัดการอินพุตของคุณคิดว่ามันกำลังได้รับอ็อกเท็ต UTF-8 ยกเว้นว่ามันเป็นจริงและคุณไม่ต้องการให้ตัวจัดการเอาต์พุตของคุณเป็น UTF-8 ถ้าสิ่งที่อ่านจากพวกเขาสามารถจัดการ UTF-8 ได้ . Perl ไม่มีทางที่จะรู้สิ่งเหล่านั้น นั่นเป็นเหตุผลว่าทำไมคุณถึงเป็นโปรแกรมเมอร์

ฉันไม่คิดว่า Unicode ใน Perl 5 ซับซ้อนเกินไป ฉันคิดว่ามันน่ากลัวและผู้คนก็หลีกเลี่ยง มีความแตกต่าง ไปสิ้นสุดที่ฉันได้ใส่ Unicode ในการเรียนรู้ Perl 6 ฉบับและมีจำนวนมากของสิ่ง Unicode ในการเขียนโปรแกรมที่มีประสิทธิภาพ Perl คุณต้องใช้เวลาในการเรียนรู้และทำความเข้าใจกับ Unicode และวิธีการทำงาน คุณจะไม่สามารถใช้งานได้อย่างมีประสิทธิภาพ


3
ฉันคิดว่าคุณมีประเด็น: มันน่ากลัว มันควรจะเป็นอย่างไร สำหรับฉันคือการให้ Unicode การใช้ใน Perl5 ไม่ใช่ (ฉันไม่คิดว่าเป็น ASCII ภาษาแม่ของฉันต้องการอย่างน้อย iso8859-4) ฉันติดตั้ง Rakudo และทุกสิ่งที่ฉันลองด้วย UTF-8 (ในกล่องทราย จำกัด ) นี้ใช้งานไม่ได้เลย ฉันพลาดอะไรไปหรือเปล่า? ฉันเน้นมันอีกครั้ง: มันเป็นการดีที่ได้รับการสนับสนุน Unicode ที่ปรับจูนได้ดี แต่โดยส่วนใหญ่แล้วไม่จำเป็นต้องทำเช่นนั้น เพื่อขจัดความกลัวในหัวข้อวิธีหนึ่งคือทุกคนอ่านเพื่อทำความเข้าใจกับเรื่องภายใน อื่น ๆ : เรามีความเชี่ยวชาญเป็นพิเศษจึงuse utf8_everywhereทำให้ผู้คนมีความสุข ทำไมไม่ใช้ล่าสุด
สัปดาห์

3
ฉันยังคิดว่าคุณไม่มีจุด ทำงานอะไร คุณไม่จำเป็นต้องเข้าใจเรื่องภายใน คุณต้องเข้าใจexternalsและวิธีการที่คุณต้องการจัดการสตริงที่มีการเข้ารหัสที่แตกต่างกันและการเป็นตัวแทนที่แตกต่างกันของตัวละครเดียวกัน อ่านคำแนะนำของทอมอีกครั้ง ส่วนใหญ่ของสิ่งที่เขาพูดว่าฉันเดิมพันคุณจะพบว่า Rakudo ไม่ได้จัดการให้คุณ
brian d foy

1
@wk: อ่านคำตอบของ Randy อีกครั้ง เขาบอกคุณแล้วว่าข้อ จำกัด คืออะไร
brian d foy

2
@ brian d foy: ฉันคิดว่าข้อ จำกัด เหล่านั้นดีเช่น tchrist พูดว่าไม่มี bullet มายากลทุกด้าน (ฉันยอมรับ: ฉันไม่เห็นพวกเขาส่วนใหญ่ก่อนถามคำถามนี้ที่นี่) ดังนั้นเมื่อเราครอบคลุมเนื้อหาพื้นฐานมากมายเช่น utf8 :: all, ไม่จำเป็นสำหรับทุกคนที่จะสร้างหม้อไอน้ำขนาดใหญ่ของเขาเองเพื่อรับพื้นฐานในการจัดการ utf8 เท่านั้น ด้วย "ไม่กลัวเลย" ฉันหมายถึง: ทุกคนสามารถเริ่มโครงการของเขาได้โดยรู้ว่าพื้นฐานครอบคลุม ใช่คุณพูดถูกปัญหายังคงมีอยู่มากมาย แต่เมื่อเริ่มต้นได้ง่ายขึ้นเราจะมีผู้คนจำนวนมากที่เกี่ยวข้องในการแก้ปัญหาเหล่านั้น IMHO
สัปดาห์

1
@wk - เพียง "ผิด" กับ "utf8: all" หรือ "uni :: perl เป็นเพียงคนเดียว - พวกเขาไม่ได้อยู่ใน CORE - ดังนั้นทุกคนต้องติดตั้งจาก CPAN และถ้าคุณคิดว่านี่ไม่ใช่เรื่องใหญ่ ตกลง - โปรดคิดใหม่ - ใช่มันง่ายกว่าการใช้ utf8 กับโมดูลตัวช่วยโดยที่ CORE Perl ยังคงมีการสนับสนุน Unicode - แต่ซับซ้อนมากมากและนี่เป็นสิ่งที่ผิด
jm666

28

ในขณะที่อ่านกระทู้นี้ฉันมักจะได้รับความประทับใจว่าผู้คนกำลังใช้ " UTF-8 " เป็นคำพ้องกับ " Unicode " โปรดแยกความแตกต่างระหว่าง "รหัส - คะแนน" ของ Unicode ซึ่งเป็นญาติที่ขยายใหญ่ของรหัส ASCII และ "การเข้ารหัส" ต่างๆของ Unicode และมีบางส่วนของพวกเขาซึ่ง UTF-8, UTF-16และUTF-32เป็นคนปัจจุบันและอีกไม่กี่ล้าสมัย

ได้โปรดมี UTF-8 (รวมถึงการเข้ารหัสอื่น ๆ) และมีความหมายในอินพุตหรือเอาต์พุตเท่านั้น ภายในตั้งแต่ Perl 5.8.1 สตริงทั้งหมดจะถูกเก็บไว้เป็น Unicode "รหัสจุด" จริงคุณต้องเปิดใช้งานคุณสมบัติบางอย่างตามที่กล่าวไว้ก่อนหน้านี้


19
ฉันเห็นด้วยกับผู้คนบ่อยครั้งที่ทำให้สับสนUɴɪᴄᴏᴅᴇกับ UTF-8⧸16⧸32 แต่มันเป็นเรื่องพื้นฐานและที่สำคัญไม่เป็นความจริงที่Uɴɪᴄᴏᴅᴇเป็นเพียงชุดอักขระที่ขยายใหญ่ขึ้นเมื่อเทียบกับᴀsᴄɪɪ ที่ส่วนใหญ่ที่ไม่มีอะไรมากไปกว่าเพียงɪsᴏ-10646 Uɴɪᴄᴏᴅᴇประกอบด้วยสิ่งอื่น ๆ อีกมากมาย : กฎสำหรับการเรียงหน้า, casefolding, รูปแบบการทำให้เป็นมาตรฐาน, กลุ่มกราฟ, การแบ่งคำ, & บรรทัดสคริปต์, สคริปต์, equivs ตัวเลข, ความกว้าง, bidirectionality, ตัวแปร glyph, บริบท, โลแคล, regexes อีกมากมาย‼
tchrist

15
@tchrist: ขั้นตอนแรกคือการรับข้อมูลเข้าสู่โปรแกรมของคุณและออกสู่โลกภายนอกโดยไม่ต้องทิ้งมันลงไป จากนั้นคุณสามารถกังวลเกี่ยวกับการเรียงพับกรณีพับสายพันธุ์ glyph ฯลฯ ขั้นตอนทารก
jrockway

7
ฉันเห็นด้วยการรับ Perl ไม่ให้ถังขยะใส่หรือส่งออกจะต้องมีความสำคัญอันดับแรก สิ่งที่ฉันต้องการคือให้มีโมดูลหรือ pragma ที่สามารถรวบรวมบทสนทนาสมมติต่อไปนี้: "- เรียน Perl สำหรับโปรแกรมนี้อินพุตและเอาต์พุตทั้งหมดจะเป็น UTF-8 โดยเฉพาะคุณช่วยกรุณาอย่าทิ้งข้อมูลของฉัน? - มีเพียงคุณเท่านั้นที่พูด UFT-8 คุณแน่ใจหรือไม่ - ใช่ - จริง ๆ จริง ๆ หรือไม่ - แน่นอน - และคุณยอมรับว่าฉันอาจประพฤติแปลก ๆ ถ้าฉันให้บริการข้อมูลที่ไม่ใช่ UTF-8 - ใช่แล้ว - โอเคถ้าอย่างนั้น."
hlovdal

10

มีรหัสโบราณจำนวนมากที่น่ากลัวอย่างแท้จริงในป่าซึ่งส่วนใหญ่เป็นในรูปแบบของโมดูล CPAN ทั่วไป ฉันพบว่าฉันต้องระวังการเปิดใช้ Unicode อย่างถี่ถ้วนหากฉันใช้โมดูลภายนอกที่อาจได้รับผลกระทบและยังคงพยายามระบุและแก้ไขความล้มเหลวที่เกี่ยวข้องกับ Unicode ในสคริปต์ Perl หลายตัวที่ฉันใช้เป็นประจำ (โดยเฉพาะiTiVoล้มเหลว ไม่ดีกับทุกสิ่งที่ไม่ใช่ ASCII แบบ 7 บิตเนื่องจากปัญหาการแปลงรหัส)


ฉันหมายถึงใช้-Cตัวเลือกเพื่อให้แน่ใจว่า Perl อยู่บนหน้าเดียวกันกับผม Unicode ที่ชาญฉลาดเพราะผมให้มีมันตัดสินใจที่จะใช้มาตรฐาน ISO 8859/1 แทน Unicode แม้ว่าฉันกำลังตั้งค่าอย่างชัดเจน$LANGและ$LC_ALLถูกต้อง (สิ่งนี้อาจสะท้อนข้อผิดพลาดในไลบรารีโลแคลของแพลตฟอร์ม) ไม่ว่าจะเป็นอะไรก็ตามมันเป็นเรื่องที่น่ารำคาญอย่างมากที่ฉันไม่สามารถใช้ iTivo กับโปรแกรมที่มีการเน้นเสียงในพวกเขาได้เพราะสคริปต์ Perl ที่ทำงานผิดพลาด
geekosaur

3
โดดเดี่ยว-Cโดยไม่มีตัวเลือกเป็นรถและผิดพลาดได้ง่าย คุณทำลายโลก ตั้งค่าสภาพPERL5OPTแวดล้อม-Cและคุณจะเห็นสิ่งที่ฉันหมายถึง เราลองใช้วิธีนี้ใน v5.8 และมันก็เป็นหายนะ คุณไม่สามารถและต้องไม่บอกโปรแกรมที่ไม่คาดหวังว่าตอนนี้พวกเขากำลังจัดการกับ Unicode ไม่ว่าพวกเขาจะชอบหรือไม่ก็ตาม นอกจากนี้ยังมีปัญหาด้านความปลอดภัย อย่างน้อยที่สุดสิ่งใดก็ตามที่print while <>จะแตกถ้าผ่านข้อมูลไบนารี ดังนั้นรหัสฐานข้อมูลทั้งหมดก็เช่นกัน นี่เป็นความคิดที่แย่มาก
tchrist

1
ฉันพูดโดยทั่วไปจริง ๆ แล้วไม่เฉพาะเจาะจง-Cโดยไม่มีตัวเลือก -CSDAภาวนาเฉพาะผมเคยทำงานกับเป็น ที่กล่าวว่าฉันติดอยู่กับ 5.8.x เป็นเวลานาน (สวัสดี MacPort ... ) ดังนั้นอาจเป็นส่วนหนึ่งของมัน
geekosaur

1
ฉันรันด้วย PERL_UNICODE ตั้งค่าเป็น SA คุณไม่สามารถตั้งค่าเป็น D
tchrist

@tchrist: บาง varmint Perl ได้รับรหัสการโพสต์แสดง -CSDA และ PERL_UNICODE = SDA การใช้งาน โปรดใช้อิทธิพลของคุณในชุมชน เขาจะต้องหยุด!
แอชลีย์

1

คุณควรเปิดใช้งานคุณสมบัติสตริง Unicode และนี่คือค่าเริ่มต้นหากคุณใช้ v5.14

คุณไม่ควรใช้ตัวระบุยูนิโค้ดจริงๆ สำหรับโค้ดต่างประเทศผ่าน utf8 เนื่องจากไม่ปลอดภัยใน perl5 เฉพาะ cperl เท่านั้นที่ได้รับสิทธิ์ ดูเช่นhttp://perl11.org/blog/unicode-identifiers.html

เกี่ยวกับ utf8 สำหรับ filehandles / streams ของคุณ: คุณต้องตัดสินใจด้วยตัวเองในการเข้ารหัสข้อมูลภายนอกของคุณ ไลบรารีไม่สามารถรู้ได้และเนื่องจากแม้แต่ libc ยังสนับสนุน utf8 ข้อมูล utf8 ที่เหมาะสมจึงเป็นของหายาก มี wtf8 มากขึ้นความคลาดเคลื่อนของ utf8 รอบ ๆ หน้าต่าง

BTW: Moose ไม่ได้เป็น "Modern Perl" จริง ๆ พวกเขาเพิ่งขโมยชื่อ Moose นั้นสมบูรณ์แบบ Larry Wall สไตล์โพสต์โมเดิร์น perl ผสมกับ Bjarne Stroustrup สไตล์ทุกอย่างดำเนินไปพร้อมกับความผิดปรกติของไวยากรณ์ perl6 ที่เหมาะสมเช่นใช้สตริงชื่อตัวแปรซินแท็คซ์ฟิลด์ที่น่ากลัว การใช้งานที่เหมาะสม cperl และ perl6 เป็น perls สมัยใหม่ที่แท้จริงซึ่งรูปแบบตามหน้าที่และลดการใช้งานและปรับให้เหมาะสม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.