קלט/פלט#
ה-filehandle הוא הגבול בין עולם הטקסט של תוכניתך לבין העולם החיצוני של בתים. לעשות Unicode נכון פירושו להקים את הגבול הזה כראוי בעת open (או באמצעות binmode), כך ש-print ו-readline רגילים כבר מדברים בקידוד הנכון.
שכבות PerlIO#
כל filehandle נושא מחסנית של שכבות - חלקי מנגנון קטנים שמשנים בתים כשהם חוצים את הגבול. הרלוונטיות ל-Unicode הן:
:raw- ללא טרנספורמציה. בתים נכנסים, בתים יוצאים.:utf8- בדוק שהבתים הנקראים מרכיבים UTF-8 תקין וסמן את המחרוזת כטקסט. בטח במשתמש שלא ייצר UTF-8 בלתי-תקין בכתיבות.:encoding(ENCODING)- פענח בקריאה, קודד בכתיבה, עבור כל קידוד בעל שם. דוחה קלט פגום כברירת מחדל.:crlf- תרגם"\r\n"ל-"\n"בקריאה,"\n"ל-"\r\n"בכתיבה. ב-Linux זה אינו פעיל; ב-Windows זוהי ברירת המחדל ל-handles של טקסט.
:encoding(UTF-8) הוא מה שאתה כמעט תמיד רוצה. העדף אותו על פני השכבה החשופה :utf8 - הצורה :encoding(...) מאמתת, :utf8 לא.
פתיחת קובץ עם קידוד#
הצורה בעלת שלושת הארגומנטים של open מקבלת מצב שיכול לכלול שכבות:
open my $in, "<:encoding(UTF-8)", "input.txt" or die "open: $!";
open my $out, ">:encoding(UTF-8)", "output.txt" or die "open: $!";
while (my $line = <$in>) {
chomp $line; # characters, not bytes
print $out uc $line, "\n"; # encoded on the way out
}
כל readline מ-$in מחזיר מחרוזת טקסט. כל print ל-$out מקודד ל-UTF-8 על הקו. גוף הלולאה רואה רק תווים - בלי decode, בלי encode, בלי מניית בתים בטעות.
התאמה לאחור עם binmode#
אם ה-filehandle כבר פתוח - לדוגמה הזרמים הסטנדרטיים, או handle שנמסר לך על ידי מודול אחר - צרף את השכבה באמצעות binmode:
binmode STDIN, ":encoding(UTF-8)";
binmode STDOUT, ":encoding(UTF-8)";
binmode STDERR, ":encoding(UTF-8)";
עשה זאת פעם אחת, בראש התוכנית, לפני כל I/O על אותם handles. לאחר מכן הזרמים הסטנדרטיים מתנהגים כמו קובץ שנפתח עם שכבת קידוד.
הפרגמה use open#
כתיבת אותה שכבת :encoding(UTF-8) על כל open היא רועשת. הפרגמה open מגדירה את שכבות ברירת המחדל לכל הפתיחות הבאות בתחום העוטף:
use open ":std", ":encoding(UTF-8)";
התג :std גם משכבת מחדש את STDIN, STDOUT ו-STDERR במקום, כך שאתה מקבל את האפקט של שלוש קריאות binmode וברירת מחדל לכל open מאוחר יותר בשורה אחת.
זוהי שורת-ה-one-liner בראש סקריפט מודרני מודע-Unicode:
use utf8;
use open ":std", ":encoding(UTF-8)";
use utf8- ליטרלים בקובץ מקור זה הם UTF-8.use open ":std", ":encoding(UTF-8)"- stdin/stdout/stderr וכל פתיחה מאוחרת יותר מוגדרים כברירת מחדל ל-UTF-8 על הקו.
תוכל גם לדחוף I/O ל-UTF-8 מחוץ לתוכנית באמצעות משתנה הסביבה PERL_UNICODE. האותיות I, O, E בוחרות את stdin, stdout ו-stderr בנפרד, S בוחר את שלושתם בבת אחת באופן שבו הפרגמה use open ":std" עושה, ו-A מפענח את @ARGV, כך ש-PERL_UNICODE=SA הוא בקירוב המקבילה בשורת הפקודה של ההקדמה בת שתי השורות לעיל. כדי לפענח ארגומנטים בתוך התוכנית במקום זאת, כתוב @ARGV = map { decode('UTF-8', $_, 1) } @ARGV.
מתג שורת הפקודה התואם -C (-CSA) עדיין אינו מזוהה על ידי pperl, וזו חריגה מפרל הסטנדרטית; השתמש במשתנה PERL_UNICODE או בפרגמה use open עד שהוא ימומש.
I/O בינארי לצד I/O טקסטואלי#
חלק מה-handles נושאים בתים, לא טקסט - קבצי תמונה, זרמים דחוסים, פרוטוקולי רשת שממסגרים את הקידוד שלהם עצמם. פתח את אלה כ-:raw ולעולם אל תצרף קידוד:
open my $img, "<:raw", "photo.jpg" or die "open: $!";
בתוך תוכנית אחת, חלק מה-handles יכולים להיות טקסט (:encoding(UTF-8)) ואחרים בינאריים (:raw). שמור על התוויות ברורות: handle בינארי נותן לך מחרוזות בתים, handle טקסט נותן לך מחרוזות טקסט, ו-$! הוא אותו דבר בשני המקרים.
קלט אינטראקטיבי#
מסוף אינו אומר לך באיזה קידוד הוא מקליד. ב-Linux מודרני זה כמעט תמיד UTF-8; ב-Windows דף-הקוד של ברירת המחדל בקונסולה הוא עדיין לרוב CP1252 או CP437. ההנחה הרגילה לסקריפטים חוצי-פלטפורמה היא UTF-8, עם binmode המיושם בהפעלה:
binmode STDIN, ":encoding(UTF-8)";
אם תוכניתך חייבת לתמוך במסופים ישנים, פענח בהתבסס על משתנה הסביבה LANG או LC_CTYPE, או קבל דגל --encoding. אין זיהוי-אוטומטי נייד.
בדיקת שכבות#
כדי לראות אילו שכבות נמצאות על handle, השתמש ב-PerlIO::get_layers:
use PerlIO;
my @layers = PerlIO::get_layers(\*STDOUT);
print "@layers\n"; # e.g. unix perlio encoding(utf-8-strict)
שימושי כשתוכנית מייצרת בחשאי פלט מקודד-כפול ואתה רוצה לגלות לאיזה handle יש את שכבת ההפתעה עליו.