# ברירה ברירה היא האופרטור `|`. הוא בוחר בין שתי תת־תבניות או יותר באותו מיקום. ```perl "cats and dogs" =~ /cat|dog|bird/; # matches 'cat' "cats and dogs" =~ /dog|cat|bird/; # matches 'cat' ``` סדר החלופות אינו משנה *היכן* התבנית הכוללת מתאימה. המנוע עדיין מכבד את הכלל ״המיקום המוקדם ביותר מנצח״ — שתי התבניות שלמעלה מתאימות במיקום 0 כי זה המיקום המוקדם ביותר שבו חלופה כלשהי יכולה להתאים. ## החלופה השמאלית ביותר מנצחת במיקום נתון בתוך מיקום התחלה יחיד, החלופות נבדקות משמאל לימין והראשונה שמצליחה היא זו שנבחרת: ```perl "cats" =~ /c|ca|cat|cats/; # matches 'c' — first alternative wins "cats" =~ /cats|cat|ca|c/; # matches 'cats' — first wins, longer ``` אם חלופה אחת היא קידומת של אחרת ורוצים את ההתאמה הארוכה יותר, יש למקם אותה ראשונה. המנוע אינו מסתכל מעבר לחלופה המוצלחת הראשונה במיקום הנוכחי. זוהי התנהגות *NFA מסורתי*, וזה מה ש־Perl, PCRE2, Python ורוב המנועים המודרניים מיישמים. מנועים תואמי־POSIX (בעיקר מימושי `awk` ו־`grep` מסוימים) עוקבים אחר כלל *הארוך-משמאל* במקום — הם יתאימו את `cats` ללא קשר לסדר החלופות. בפרק [cross-engine](cross-engine.md) מופיעה ההשוואה. פרידל מנסח זאת בתמציתיות: > ברירה חמדנית היא לא־חמדנית ב־NFA מסורתי. התבנית `tour|to|tournament` מול `three tournaments won` מתאימה את `tour`, לא את `tournament`. החלופה הראשונה מצליחה והמנוע מתחייב אליה; חלופות ארוכות יותר בהמשך הרשימה אינן נבדקות אף פעם. ## השלכות על הסדר ברירה שהיא חלק מתבנית גדולה יותר עשויה לקבל את ביצועיה ואת נכונותה מסדר החלופות: - **ספציפיות תחילה.** כאשר רוצים את הארוכה ביותר מבין כמה קידומות, יש למקם את הארוכה ביותר ראשונה. `/web|website|websites/` מתאימה את `web` אפילו על הקלט `website`; `/websites|website|web/` מתאימה את `websites`. - **המקרה הנפוץ תחילה.** ברירה נבדקת משמאל לימין; אם 90% מהקלטים פוגעים בחלופה 3, המנוע מבזבז זמן על חלופות 1 ו־2 בכל פעם. יש לסדר מחדש לפי תדירות. - **לכידות אחיות.** כאשר החלופות לוכדות, הסדר משפיע על איזה `$n` נקבע — ראו *ברירה ולכידה* למטה. ## כלל פורמלי לשילוב חלקים ״Combining RE Pieces״ של `perlre` מספק את הניסוח המדויק שביסוד הכלל ״השמאלי ביותר מנצח״. עבור שני חלקי תבנית `S` ו־`T`: > כאשר `S` יכול להתאים, זוהי התאמה טובה יותר מאשר כאשר רק `T` יכול להתאים. זוהי הגרסה הפורמלית של הכלל. ״טובה יותר״ פירושו שהמנוע מעדיף אותה. עבור שתי התאמות `S`, חל אותו סידור פנימי (כללי חמדנות בתוך החלופה); באותו אופן גם עבור התאמות `T`. בין חלופות, *קיומה של התאמת S מוצלחת שולל את שקילת T*. זו הסיבה ש־`S|T` אינה ניתנת לסידור מחדש על ידי המנוע מיוזמתו: Perl אינה מחפשת את החלופה ה *טובה ביותר* על פני הדיסיונקציה — היא מתחייבת ל־`S` בכל פעם ש־`S` מצליחה. ## קדימות קיבוץ מול ברירה ל־`|` יש קדימות נמוכה מאוד. הוא מפצל את התבנית ברמה ה *חיצונית ביותר* המכילה אותו: ```perl /ab|cd/; # 'ab' OR 'cd' /^ab|cd$/; # '^ab' OR 'cd$' — probably not what you meant! /^(ab|cd)$/; # '^' + ('ab' or 'cd') + '$' — what you meant ``` כדי לצמצם ברירה לחלק מתבנית, יש לעטוף אותה בקבוצה. קבוצה לא־לוכדת `(?:…)` עדיפה אלא אם יש צורך בלכידה: ```perl /house(?:cat|keeper)/; # 'housecat' or 'housekeeper' /house(cat|keeper)/; # same, but $1 will be 'cat' or 'keeper' ``` הקבוצה יוצרת תחום מקומי עבור `|`. מחוץ לקבוצה `|` חוזר לתפקידו ברמה העליונה: ```perl /^(?:foo|bar|baz)$|^xyz$/; # ('foo'/'bar'/'baz') or 'xyz' ``` ## חלופות ריקות חלופה ריקה מתאימה את המחרוזת הריקה — תכסיס שימושי עבור ״זה או כלום״: ```perl /house(cat|)/; # 'housecat' or 'house' /(19|20|)\d\d/; # '19xx', '20xx', or just 'xx' ``` סגנון מודרני מעדיף `(?:…)?` על פני `(?:…|)`; הם שקולים, אך צורת ה־`?` ברורה יותר: ```perl /house(?:cat)?/; # same as house(cat|), no capture ``` יש לשים לב לעלות החזרה לאחור כאשר חלופה ריקה משולבת עם כמת — המנוע עלול לחקור מחדש את אותו מיקום פעמים רבות. ראו את פרק [performance](performance.md) על סיום התאמת אורך אפס. ### הערה בין־מנועית POSIX קפדני, `lex`, ורוב מימושי `awk` הישנים *אוסרים* חלופות ריקות — `(this|that|)` הוא שגיאת תחביר. Perl 5.42, PCRE2, ה־crate של `regex` ב־Rust, `re` של Python, ומימושי מנועים מודרניים מקבלים אותן. אם תבנית צריכה להיות ניידת לכלי POSIX ישנים יותר, יש לכתוב `(?:this|that)?` במקום — זה מבטא את אותו רעיון והוא נייד בין המנועים שאינם מקבלים אף אחת מהצורות. ## ברירה בתוך מחלקות תווים מחלקות תווים הן כמעט תמיד מה שרוצים כאשר בוחרים בין תווים בודדים. `/a|b|c/` ו־`/[abc]/` מתאימות את אותן המחרוזות, אך `[abc]` מהיר יותר, תמציתי יותר וברור יותר: ```perl /a|b|c/; # works, but verbose /[abc]/; # use this ``` ברירה מיועדת לחלופות הארוכות מתו אחד (או כאלה שהן עצמן תבניות). כאשר כל חלופה היא תו בודד, יש להשתמש במחלקה. המנוע מתייחס למחלקה כבחירה אטומית *יחידה*; לברירה כ־N בחירות שיש לחקור בסדר. ## פירוק קידומת משותפת תבנית כמו `/this|that|then|those/` מסכלת את אופטימיזציית בדיקת המחרוזת הקבועה של המנוע: אין קידומת מילולית שהמנוע יכול לסרוק בזול. שכתוב כדי לחשוף את הקידומת המשותפת הופך את הברירה למשהו שהאופטימייזר יכול לעבוד איתו: ```perl /this|that|then|those/; # no common prefix visible /th(?:is|at|en|ose)/; # common prefix 'th' exposed ``` שתי התבניות מתאימות את אותן המחרוזות, והשנייה מהירה משמעותית על קלטים גדולים. המנוע סורק אחר `th` בעזרת Boyer-Moore, ואז מריץ את הברירה הקטנה רק במיקומי המועמדים. הטכניקה הכללית: 1. למצוא את הקידומת המילולית הארוכה ביותר המשותפת לכל החלופות. 2. להוציא אותה אל מחוץ לברירה. 3. לעטוף את היתרה ב־`(?:…)` כך שהברירה תישאר מקומית. עבור רשימות של מילים עם מספר קידומות שונות, ניתן ליישם את השכתוב באופן רקורסיבי. עבור רשימות ארוכות מאוד, ראו את הסעיף על התאמת מחרוזות רבות בפרק [performance](performance.md) — כאשר הרשימה מגיעה לאלפים, מנגנון התאמה ייעודי מנצח כל ברירה. ## ברירה ולכידה רק חלופה אחת בתוך קבוצה יכולה להתאים בכל פעם, ולכן הקבוצה לוכדת את החלופה המתאימה: ```perl if ("bert" =~ /(cat|dog|bert|ernie)/) { print "matched $1\n"; # matched bert } ``` קבוצות אחיות מחוץ לברירה שומרות על המספור הרגיל שלהן: ```perl /^(\w+):\s*(yes|no|maybe)$/; # $1 = the key, $2 = the verdict ``` בתוך ברירה מקוננת, הקבוצות ממוספרות משמאל לימין לפי הסוגר הפותח, אפילו בין ענפים: ```perl /(a)|(b)/; # On match of 'a': $1 = 'a', $2 undef # On match of 'b': $1 undef, $2 = 'b' ``` יש לבדוק עם `defined $n`, לא עם ערך אמת — לכידה ריקה שונה מלכידה נעדרת. ## איפוס ענפים: `(?|…)` תבניות לכידה מקבילה הן הסיבה הרגילה לבחור ב־`(?|…)`. בתוך `(?|…)`, כל ענף מתחיל למספר את הלכידות שלו באותה משבצת. אחרי הקבוצה, המספור מתחדש באחד מעבר למקסימום על פני כל הענפים. ```perl # Without (?|…): need to know which branch matched. if ($time =~ /(\d\d|\d):(\d\d)|(\d\d)(\d\d)/) { my ($h, $m) = ($1, $2); ($h, $m) = ($3, $4) unless defined $h; } # With (?|…): $1 and $2 come from whichever branch matched. if ($time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))/) { my ($h, $m) = ($1, $2); } ``` עם חלק קבוע נגרר: ```perl if ($time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))\s+([A-Z]{3})/) { # $1 = hours, $2 = minutes, $3 = zone (numbered after the group) print "hour=$1 minute=$2 zone=$3\n"; } ``` כללים בתוך `(?|…)`: - כל ענף ממספר את קבוצות הלכידה שלו באופן עצמאי החל מספירת הקבוצה הנוכחית. - אחרי הקבוצה, המספור החיצוני ממשיך באחד גבוה יותר מהספירה המקסימלית שהושגה בכל ענף. - קבוצות בשם שומרות על שמותיהן; ניתן לחזור על שם בין ענפים. יש להשתמש ב *אותם שמות באותו סדר* בכל ענף, אחרת צצות הפתעות (ראו את פרק [groups and captures](groups-and-captures.md)). איפוס ענפים הוא הדרך הנקייה ביותר לבטא ״לפענח X באחד ממספר פורמטים שקולים, ואז לגשת לאותם משתנים לאחר מכן״. ## ברירה ב־`split` `split` מקבלת תבנית של ביטוי רגולרי, כך שברירה עובדת גם שם: ```perl my @words = split /\s+|-/, "one-two three four-five"; # ('one', 'two', 'three', 'four', 'five') ``` אם תבנית המפריד מכילה קבוצות לכידה, split כוללת את הטקסט הנלכד ברשימת הפלט — לעיתים מפתיע. יש להשתמש ב־`(?:…)` אלא אם רוצים בכך: ```perl split /(?:\s+|-)/, "a-b c"; # ('a', 'b', 'c') split /(\s+|-)/, "a-b c"; # ('a', '-', 'b', ' ', 'c') ``` הצורה הלוכדת היא לעיתים מה שרוצים — שמירת המפרידים המדויקים בין השדות. ברוב המקרים רוצים לא־לוכדת. ## סיכום - `|` מפריד בין חלופות; השמאלית ביותר שמתאימה במיקום הנוכחי מנצחת. - יש לעטוף ברירות ב־`(?:…)` כדי למקם אותן. - יש להעדיף מחלקות תווים על פני ברירות של תו בודד. - יש להוציא קידומות משותפות אל מחוץ לברירה כאשר רוצים שאופטימיזציית הסריקה המילולית של המנוע תפעל. - `(?|…)` מאפס את מספור הלכידות בין ענפים — יש להשתמש בו כאשר הענפים לוכדים את אותם שדות מושגיים. ## ראו גם - פרק [groups and captures](groups-and-captures.md) — מספור לכידות בתוך `(?|…)`, ושאר מנגנון הלכידה־בשם. - פרק [performance](performance.md) — סידור לפי סבירות, פירוק קידומת משותפת, והתאמת מחרוזות רבות. - פרק [cross-engine](cross-engine.md) — הבדלי תחביר ברירה בין משפחות מנועים. - [`split`](../../p5/core/perlfunc/split.md) — ברירה כתחביר מפריד.