טיפול ב־locale#
locale הוא מערכת המוסכמות התרבותיות שתוכנית עוקבת אחריהן כשהיא ממיינת טקסט, מחליפה רישיות, מעצבת מספרים וכסף, נוקבת בשמות ימי השבוע, או כותבת הודעת שגיאה. אותו מערך מילים ממוין באופן אחד תחת locale שוודי ובאופן אחר תחת locale גרמני; המספר שתים־עשרה וחצי מודפס כ־12.5 במדינה אחת וכ־12,5 באחרת. טיפול ב־locale הוא האופן שבו Perl מאפשרת לתוכנית יחידה להסתגל למוסכמות הללו בזמן ריצה במקום לקבע בקוד את הכללים של מדינה אחת.
כברירת מחדל PetaPerl מתעלמת מ־locale לחלוטין: כל פעולה מובנית מתנהגת באותו אופן ללא תלות בסביבת המשתמש, בעזרת מוסכמות C/POSIX (collation של ASCII, . כנקודה העשרונית, שמות חודשים באנגלית). מצטרפים למודעות ל־locale, תחום לקסיקלי אחד בכל פעם, באמצעות הפרגמה use locale. עמוד זה מכסה מה הפרגמה הזו מפעילה, אילו פעולות היא משפיעה עליהן, כיצד לקבוע ולבחון את ה־locale הפעיל, והיכן locale ו־Unicode מתממשקים.
מהו locale#
ספריית ה־C של המערכת מחלקת את המוסכמות התרבותיות לקטגוריות בלתי־תלויות, כל אחת בשם LC_ ואחריו התחום שעליו היא חולשת. מיון (LC_COLLATE) נפרד מכללי רישיות (LC_CTYPE), שנפרדים מעיצוב מספרים (LC_NUMERIC), וכן הלאה. locale הוא צרור הגדרות בעל שם - de_DE.UTF-8, sv_SE.UTF-8, C - ומעבר אליו עשוי לשנות את כל הקטגוריות בבת אחת או רק את אלו שבחרת. הקטגוריות ש־PetaPerl מכבדת מפורטות בטבלת הקטגוריות שלהלן.
הפרגמה use locale#
התנהגות רגישה ל־locale היא כבויה כברירת מחדל ומתוחמת לקסיקלית. use locale מפעילה אותה מאותה נקודה ועד סוף הבלוק המקיף (או הקובץ); no locale מכבה אותה שוב עבור שארית התחום שלה. שום דבר מחוץ לתחום הלקסיקלי אינו מושפע - מודול שאינו מציין use locale שומר על התנהגות ברירת המחדל של C-locale גם כשהוא נקרא מקוד שכן ציין זאת.
use locale; # locale-aware from here down
my @sorted = sort @words; # collates per LC_COLLATE
{
no locale; # back to codepoint order in this block
my @plain = sort @words;
}
ללא הפרגמה, sort, lc, uc, printf והשאר משתמשים בכללי C-locale קבועים ללא קשר למה שהסביבה אומרת. זוהי ברירת מחדל בטיחותית מכוונת: תוכנית מפיקה את אותו פלט בכל מכונה עד שהיא מבקשת במפורש לעקוב אחר המוסכמות המקומיות.
הפרגמה קובעת רמז ברמת הוראה, בדיוק כפי ש־Perl מהמעלה־הזרם עושה, כך שקובץ יחיד יכול לערבב חופשית אזורים מודעי locale ואזורים עיוורי locale. ההגדרה נעה עם התחום הלקסיקלי, לא עם מחסנית הקריאות.
קטגוריות locale#
כל קטגוריה שולטת בקבוצה נבדלת של פעולות. use locale מפעילה את כולן בבת אחת; בוחרים איזה locale פעיל לכל קטגוריה דרך setlocale. עמודת ״הפעולות המושפעות״ מקשרת לעמודי הייחוס שבהם ההתנהגות מתועדת במלואה - שם נמצאים הכללים הספציפיים ל־locale של כל פעולה מובנית.
קטגוריה | חולשת על | פעולות מושפעות |
|---|---|---|
| סדר מיון והשוואה של מחרוזות |
|
| סיווג תווים ומיפוי רישיות | |
| נקודה עשרונית וקיבוץ ספרות | |
| מוסכמות עיצוב מטבע |
|
| שמות ימים וחודשים, פריסת תאריך | |
| שפת מחרוזות שגיאת המערכת |
LC_ALL אינו קטגוריה בפני עצמו אלא קיצור שקובע את כל הקטגוריות בבת אחת.
שים לב לאי־סימטריה אחת שמכשילה אנשים: LC_NUMERIC משנה כיצד מספרים מעוצבים לפלט, אך קוד המקור של Perl עצמו והניתוח המספרי שלו תמיד משתמשים ב־. כמפריד העשרוני. סקריפט שקורא 12,5 מקובץ של locale גרמני עדיין צריך לתרגם את הפסיק עצמו לפני שיתייחס אליו כמספר - ה־locale אינו גורם ל־"12,5" + 0 להניב 12.5. ראה מספרים ומחרוזות.
קביעת ה־locale#
use locale אומרת עקוב אחר ה־locale; היא אינה אומרת איזה locale. הבחירה הזו מגיעה מהסביבה כברירת מחדל, וניתן לתשאל אותה או לעקוף אותה דרך המודול POSIX.
setlocale בוחרת את ה־locale הפעיל עבור קטגוריה. הקריאה הניבית מכבדת את סביבת המשתמש (LANG, LC_*):
use POSIX qw(setlocale LC_ALL LC_COLLATE);
setlocale(LC_ALL, ""); # adopt the environment's locale
my $cur = setlocale(LC_COLLATE); # query the active collation
setlocale(LC_COLLATE, "sv_SE.UTF-8"); # force one explicitly
localeconv מחזירה האש המתאר את מוסכמות ה־LC_NUMERIC וה־LC_MONETARY הפעילות - הנקודה העשרונית, מפריד האלפים, סמל המטבע, והשאר - כך שתוכנית יכולה לעצב ערכים בעצמה כשאין פעולה מובנית שעושה זאת ישירות.
I18N::Langinfo חושף את langinfo, הקורא פריטים בודדים מתוך ה־locale הנוכחי: השם המתורגם של יום בשבוע או חודש (DAY_1, MON_1), מחרוזת פורמט התאריך, תו הבסיס, סמל המטבע. זהו הבן־לוויה הצר, פריט־בכל־פעם, של localeconv.
locale ו־Unicode#
טיפול ב־locale ו־Unicode הם שתי תשובות שונות ל״מהו תו״, והם מתממשקים בדרכים שכדאי להבין לפני שמשלבים ביניהם. הטיפול המלא - כיצד use utf8, שכבות קלט/פלט של UTF-8, וכללי LC_CTYPE של locale מתחברים, והמלכודות שצצות כשהם חלוקים - נמצא במדריך Unicode. התחל ב־מחרוזות וקידודים ב־Unicode וב־פרק המלכודות; פרק regex והתכונות מכסה כיצד \w ומחלקות התווים מתנהגות תחת כל מודל.
דליפות locale ובטיחות#
locale הוא מצב גלובלי־לתהליך בספריית ה־C שמתחת, ולכן קריאת setlocale שנעשית בכל מקום משנה את ה־locale בכל מקום בתהליך - חוצה גבולות מודולים, לא רק את התחום שקרא לה. נובעות מכך שתי השלכות:
use localeבטוחה לתיחום;setlocaleאינה. הפרגמה לקסיקלית ואינה מדליפה דבר. קריאתsetlocaleהיא תופעת לוואי גלובלית - אם ספרייה קובעת אתLC_NUMERICל־locale עם פסיק עשרוני ושוכחת לשחזר אותו, כלprintfמאוחר יותר בתוכנית מושפע. שמור ושחזר סביב שינוי זמני:my $saved = setlocale(LC_NUMERIC); setlocale(LC_NUMERIC, "de_DE.UTF-8"); # ... locale-sensitive work ... setlocale(LC_NUMERIC, $saved);
שמות locale לא מהימנים הם קלט לא מהימן. העברת מחרוזת המסופקת מהסביבה ישירות ל־
setlocaleמאפשרת לסביבה לכוון את עיצוב התוכנית שלך. בהקשר רגיש מבחינת אבטחה, אמת את השם או קבע את ה־locale במפורש במקום לקרוא ל־setlocale(LC_ALL, "").
ביצוע מקבילי ו־locale#
PetaPerl ממקבלת אוטומטית חלק מהלולאות המספריות על פני worker threads. הדבר לעולם אינו משפיע על קוד רגיש ל־locale, מעצם הבנייה. פעולות שתוצאותיהן תלויות ב־locale הנוכחי - sort עם ה־collation המוגדר כברירת מחדל, השוואת מחרוזות LC_COLLATE, קיפול אותיות lc/uc/fc, ועיצוב מספרים LC_NUMERIC - לעולם אינן עוברות הידור JIT או מיקבול אוטומטי; הן תמיד מתבצעות באופן סדרתי בפרשן מול ה־locale היחיד כלל־התהליכי. מיקבול אוטומטי מריץ אך ורק גופי לולאה מספריים, ולכן שום חישוב רגיש ל־locale אינו מופנה על פני worker threads. אינך צריך להגן על מצב ה־locale בכתיבת קוד ניתן־למיקבול: הנתיב המקבילי פשוט לעולם אינו נוגע בו.
משתני סביבה#
כשתוכנית קוראת ל־setlocale(LC_ALL, ""), ספריית ה־C קוראת את ה־locale מהסביבה בסדר עדיפות קבוע: LC_ALL עוקף כל משתנה LC_* בודד, כל משתנה LC_* קובע את הקטגוריה שלו, ו־LANG מספק את ברירת המחדל לכל קטגוריה שלא צוינה אחרת. משתנים אלו חיים ב־%ENV כמו כל ערך סביבה אחר, כך שתוכנית יכולה לבחון או להתאים אותם לפני קריאת setlocale שצורכת אותם.
משתנה | השפעה |
|---|---|
| עוקף את כל הקטגוריות |
| קובע קטגוריה אחת בעלת שם |
| ברירת מחדל לכל קטגוריה שלא נקבעה לעיל |
הבדלים מן ה-upstream#
Linux בלבד, UTF-8 נייטיבי. PetaPerl רצה רק על Linux מול ה־locales של ספריית ה־C של המערכת. מנגנון ה־locale הספציפי לפלטפורמה ש־Perl מהמעלה־הזרם נושאת עבור VMS, Windows ו־Android - מתאמי ה־locale של
Win32::, מוזרויות הקטגוריות של VMS, חלופות ה״locales אינם זמינים בפלטפורמה זו״ - אין לו מקבילה כאן והוא פשוט נעדר. יש מודל locale אחד: זה של POSIX ש־glibcשלך מספק.LC_NUMERICוניתוח מקור. כמו במעלה־הזרם, המפריד העשרוני המשמש כש־Perl מנתחת ליטרלים מספריים והמרות מחרוזת־למספר הוא תמיד., ללא תלות ב־locale; רק עיצוב הפלט מכבד אתLC_NUMERIC. PetaPerl אינה עושה חריג לכך.מיקבול אוטומטי לעולם אינו נוגע בקוד רגיש ל־locale. PetaPerl ממקבלת אוטומטית חלק מהלולאות המספריות על פני worker threads, יכולת ש־Perl מהמעלה־הזרם אינה מחזיקה. מכיוון שפעולות תלויות־locale (collation, קיפול אותיות, עיצוב מספרים) לעולם אינן עוברות הידור JIT או מיקבול, הן תמיד רצות באופן סדרתי מול ה־locale היחיד כלל־התהליכי - כך שהתכונה אינה מציגה כל חשש בטיחות locale משלה. ראה ביצוע מקבילי ו־locale לעיל.
ראו גם#
perlfunc- הפעולות המובנות שה־locale משנה את התנהגותן:sort,lc,uc,lcfirst,ucfirst,sprintf,printf.perlop- אופרטורי השוואת המחרוזות (lt,cmp, …) שמבצעים collation תחתLC_COLLATE.perlvar-%ENVמחזיק את המשתניםLANG/LC_*;$!נושא טקסט שגיאה מתורגם ל־locale.POSIX-setlocaleו־localeconv, הממשק לבחירה ולבחינה של ה־locale הפעיל.I18N::Langinfo-langinfo, לקריאת פריט מתורגם אחד (שם חודש, תו בסיס) בכל פעם.-
כיצד מודל התווים של Unicode מתייחס ל־
LC_CTYPEשל locale.