# יסודות הביטוי הרגולרי השימושי הקטן ביותר הוא מחרוזת פשוטה. `"Hello World" =~ /World/` שואל: האם המחרוזת משמאל מכילה את התבנית מימין? היא מכילה, ולכן הביטוי הוא אמת. ```perl if ("Hello World" =~ /World/) { print "matched\n"; } ``` ה־`//` עוטף את התבנית. אופרטור ה־`=~` קושר את התבנית למחרוזת שיש לבדוק. ללא אופרטור קישור, Perl מחילה את התבנית על `$_` במקום זאת. ## אופרטור ההתאמה הצורה הארוכה היא `m//`: ```perl "Hello World" =~ m/World/; "Hello World" =~ m!World!; # alternate delimiters "Hello World" =~ m{World}; # paired delimiters ``` `m` מאפשר לבחור כל מתחם שהוא. זה חשוב כאשר התבנית עצמה מכילה את המתחם ברירת־המחדל `/` — יש להשוות ```perl "/usr/bin/perl" =~ /\/usr\/bin\/perl/; # leaning toothpick syndrome "/usr/bin/perl" =~ m!/usr/bin/perl!; # clearer ``` מתחמים זוגיים (`{}`, `()`, `[]`, `<>`) קיננים, מה שמועיל כאשר התבנית מכילה את תו המתחם. ללא `m`, הקו האלכסוני המוביל הוא חובה: רק `/pat/`. עם `m`, ה־`m` המוביל הוא חובה: `m{pat}`, ולא `{pat}`. פינה קטנה אך מועילה: `m''` (גרשיים בודדים כמתחמים) הופך את התבנית ל *דמוית־מירכאה־בודדת* — אין שיבוץ משתנים, אין תווי escape של מירכאות כפולות. מועיל כאשר התבנית אמורה להכיל `$` או `@` מילוליים ואין רצון לבצע להם escape. ```perl 'price: $10' =~ m'\$\d+'; # $-as-anchor would be /$\d+/ 'price: $10' =~ m'$10'; # literal '$10' — no interpolation ``` ## אופרטורי regex אחרים `m//` הוא אחד מארבעה: | אופרטור | תכלית | |---------------------|------------------------------------| | `m//` | התאמה — האם התבנית מתאימה למחרוזת? | | `s///` | החלפה — החלפת ההתאמה במשהו אחר | | `qr//` | הידור עצם תבנית לשימוש חוזר | | `tr///` (גם `y///`) | תרגום תו־אחר־תו | `tr///` *אינו* אופרטור regex למרות שהוא שוכן באותה שכונה — הוא מבצע תרגום מחלקת־תווים, לא התאמת תבנית. הוא מוזכר לשם השלמות; ראו [`tr`](../../p5/core/perlfunc/tr.md) לסמנטיקה שלו. [`m`](../../p5/core/perlfunc/m.md), [`s`](../../p5/core/perlfunc/s.md) ו־[`qr`](../../p5/core/perlfunc/qr.md) חולקים את תחביר ה־regex המכוסה במדריך זה. ההבדלים הם במה שהם עושים *עם* התאמה מוצלחת. ## שימוש חוזר בתבנית באמצעות `qr//` `qr//` מהדר תבנית פעם אחת ומייצר עצם לשימוש חוזר. יש להשתמש בו כאשר אותה תבנית מותאמת שוב ושוב, במיוחד בלולאות: ```perl my $word = qr/\b[a-z]+\b/; for my $line (@lines) { while ($line =~ /$word/g) { print "$&\n"; } } ``` עצם ה־`qr//` המהודר מוטמע בתבניות אחרות באמצעות שיבוץ. הוא גם מאפשר לבנות תבניות מחלקים בעלי שם, מה שהופך לחיוני עבור כל regex שאורכו מעל עשר שורות בערך: ```perl my $name = qr/[A-Z][a-z]+/; my $number = qr/\d+/; my $entry = qr/$name \s+ $number/x; "Alice 42" =~ /^$entry$/; # matches ``` אותו יתרון של הידור־פעם־אחת, מבוטא ברמת ההפשטה המתאימה. ## קישור: `=~` ו־`!~` `=~` שואל ״האם יש התאמה?״. `!~` שואל ״האם יש כשל בהתאמה?״. ```perl $s = "Hello World"; print "yes\n" if $s =~ /World/; # yes print "no\n" if $s !~ /planet/; # no ``` `!~` אינו מבנה regex נפרד — הוא הקישור השלילי. הוא שקול ל־`not ($s =~ /pat/)`. ## התאמה מול `$_` אם הקישור מושמט, ההתאמה היא מול `$_`: ```perl for ("cat", "dog", "bird") { print "has an 'o'\n" if /o/; # implicit: $_ =~ /o/ } ``` זוהי דרך הביטוי המקובלת בלולאות `while (<>)`, בתוך `grep` ו־`map`, ובתוך לולאות `for` שקובעות את `$_`. ## רגישות לאותיות גדולות וקטנות והעיגון ברירת־המחדל ההתאמות רגישות לאותיות גדולות וקטנות ובלתי־מעוגנות: ```perl "Hello" =~ /hello/; # does not match — case differs "Hello" =~ /ell/; # matches — inside the string is fine ``` כדי להתאים ללא רגישות לאותיות גדולות וקטנות, יש לצרף `/i`. כדי לתחום את ההתאמה לתחילת המחרוזת או לסופה, יש להשתמש בעוגנים. שניהם מכוסים בפרקים ייעודיים. כאשר תבנית יכולה להתאים בכמה מיקומים, Perl מנסה משמאל ולוקחת את הראשון שעובד: ```perl "That hat is red" =~ /hat/; # matches 'hat' in 'That', not in 'hat' ``` הכלל ״ההתאמה השמאלית ביותר מנצחת״ הוא יסודי וגובר על כל העדפת התאמה אחרת: התאמה במיקום מוקדם יותר תמיד עדיפה על התאמה במיקום מאוחר יותר, ללא תלות בבחירות הפנימיות שעושה כל התאמה. לעיתים נקרא הדבר *תכונת ההתקדמות הצעדית* (bump-along): המנוע מנסה להתאים במיקום 0; אם הוא נכשל, הוא מתקדם למיקום 1; אם הוא נכשל, למיקום 2; וכן הלאה, ומחזיר את ההצלחה הראשונה. ## מטה־תווים רוב התווים בתבנית מתאימים את עצמם. אלה אינם: ```none { } [ ] ( ) ^ $ . | * + ? \ ``` שניים נוספים מיוחדים רק בהקשרים מסוימים: - `-` הוא מטה־תו רק בתוך מחלקת תווים, שם הוא יוצר טווח (`[a-z]`). מחוץ ל־`[…]` הוא מילולי. - `#` הוא מטה־תו רק תחת הדגל `/x`, שם הוא פותח הערה עד סוף השורה. ללא `/x` הוא מילולי. לכל מטה־תו יש משמעות מיוחדת המכוסה בהמשך. כדי להתאים עותק מילולי שלו, יש להציב לפניו לוכסן הפוך: ```perl "2+2=4" =~ /2+2/; # fails — '+' is a quantifier, needs escaping "2+2=4" =~ /2\+2/; # matches "end." =~ /end\./; # matches a literal dot "end." =~ /end./; # also matches — but . matches any character, # so this would also match "endx", "end ", etc. ``` הלוכסן ההפוך עצמו הוא מטה־תו, ולכן לוכסן הפוך מילולי בתבנית דורש `\\`: ```perl 'C:\WIN32' =~ /C:\\WIN/; # matches ``` מטה־תו שאין לו דבר מיוחד לעשות בהקשרו חוזר להתאים את עצמו. `}` רק סוגר מכמת `{…}`; מחוץ להקשר זה הוא `}` מילולי. זה נוח אך קל לקריאה שגויה; ראו *מצב מחמיר* להלן. ## מצב מחמיר: `use re 'strict'` `use re 'strict'` הופך רישול ב־regex שנסבל בעבר לשגיאות בזמן הידור. יש להשתמש בו כאשר רוצים שמהדר ה־regex יסמן תבניות *שכנראה* מתכוונות למשהו שונה ממה שנכתב: ```perl use re 'strict'; /abc{,1/; # error: unescaped '{' in non-quantifier context /(?-p)/; # error: useless negation of always-on flag /[a-]/; # error: dash at end of class ``` המצב המחמיר הוא לפי תחום לקסיקלי, ולכן ניתן להפעילו עבור מודולים עתירי־regex מבלי להשפיע על קוד אחר. הוא אינו ברירת־מחדל מכיוון שהיה שובר תבניות ישנות עובדות; קוד חדש כדאי שישקול אותו. ## רצפי escape תווים לא־מודפסים משתמשים באותם רצפי escape כמו במחרוזות במירכאות כפולות: | רצף | מתאים | |---------|----------------------------------| | `\t` | טאב | | `\n` | שורה חדשה | | `\r` | החזרת גררה | | `\f` | הזנת טופס | | `\a` | התראה (פעמון) | | `\e` | escape (`\x1B`) | | `\0` | בית NUL | | `\xHH` | בית בערך הקסדצימלי HH | | `\x{…}` | נקודת קוד Unicode בערך הקסדצימלי | | `\o{…}` | נקודת קוד אוקטלית | | `\cX` | control-X | | `\N{…}` | תו Unicode לפי שם | ```perl "1000\t2000" =~ /0\t2/; # matches "a\x{263a}b" =~ /\x{263a}/; # matches U+263A, WHITE SMILING FACE ``` הסיפור המלא של Unicode נמצא בפרק [unicode](unicode.md). ## משתנים בתבניות תבנית משובצת (כברירת מחדל) כמו מחרוזת במירכאות כפולות, כך שהמשתנים מוחלפים לפני ההתאמה: ```perl my $word = "house"; "housecat" =~ /$word/; # matches "housecat" =~ /${word}cat/; # matches — braces disambiguate ``` כדי להתאים `$` או `@` מילולי, יש לבצע לו escape: ```perl 'price: $10' =~ /\$10/; # matches a literal dollar sign ``` אם מחרוזת שסופקה על־ידי המשתמש תשובץ לתבנית ויש רצון שהמטה־תווים שלה יטופלו כמילוליים, יש להשתמש ב־[`quotemeta`](../../p5/core/perlfunc/quotemeta.md) — או במקבילה התוך־תבניתית שלו `\Q…\E`: ```perl my $input = "1+1"; "1+1=2" =~ /\Q$input\E/; # matches the literal string ``` ללא `\Q…\E` ה־`+` היה נקרא כמכמת. ## כיצד נקרא regex Perl קוראת תבנית regex בארבעה שלבים. הכרת השלבים מסבירה כמה שאלות מסוג ״מדוע זה עובד?״: 1. **שלב A**: המנתח מזהה את המתחם ומוצא את סוף התבנית. הערות `(?#…)` מוסרות. 2. **שלב B**: התבנית מנותחת כ *מחרוזת דמוית־מירכאות־כפולות* — משתנים משובצים, רצפי escape מתבשלים, `\Q…\E` מתורגם ל־escape בסגנון `quotemeta`. 3. **שלב C**: תחת `/x` או `/xx`, רווחים לבנים בלא־escape והערות שאחרי `#` מוסרים. 4. **שלב D**: מהדר ה־regex קורא את התוצאה והופך אותה לצורה הפנימית של המנוע. הסדר חשוב מכיוון ששלבים B ו־D פועלים על ייצוגים שונים. `\Q$dir\E` מתבשל בשלב B, לפני שמהדר ה־regex רואה אותו — עד לשלב D, תוכן המשתנה כבר עבר escape, ומהדר ה־regex רואה תבנית מילולית. לעומת זאת, `\U…\E` מפורש על־ידי שלב B כהוראת בישול־מחרוזת (להפוך את התוכן לאותיות גדולות), מה שכמעט בוודאות *אינו* מה שרוצים בתוך regex. המוסכמה היא: `\Q` ו־`\E` למטרות regex; `\U`, `\L`, `\u`, `\l` רק כאשר ידוע מה עושים. `(?#comment)` מוסרת לפני ששלב B רואה את התבנית כלל. `#` מילולי בתוך `(?#…)` הוא תקין. `)` מילולי אינו — ההערה מסתיימת ב־`)` הראשונה. ## ההתאמה המוקדמת ביותר מנצחת — ההתקדמות הצעדית פרידל מנסח זאת בדיוק: > ההתאמה שמתחילה הכי מוקדם מנצחת. מיקום 0 נבדק תחילה, אחר כך 1, אחר כך 2, וכן הלאה. המנוע *לעולם* אינו מעדיף התאמה מאוחרת יותר, ארוכה יותר או ״אסתטית יותר״ על פני אחת מוקדמת יותר. זה כל כך יסודי שהוא מעצב כל כלל אחר במדריך זה: - ״מכמתים חמדנים תופסים כמה שאפשר״ — *במיקום ההתחלה הנוכחי*. התפיסה מתרחשת לאחר שההתקדמות הצעדית בחרה את המיקום. - ״החלופה השמאלית ביותר מנצחת״ — *במיקום ההתחלה הנוכחי*. החלופה הנבחרת משפיעה על מה שנלכד אך לא על המקום שבו ההתאמה מתחילה. - עוגנים כמו `^` מגבילים את *אילו מיקומים חוקיים*, ולא מה מועדף מבין החוקיים. ## לומר מה שמתכוונים הנקודה החוזרת של פרידל: עמימות ב־regex גורמת הן לבעיות נכונות והן לבעיות ביצועים. הדוגמה שהוא מרבה להדגיש: ```perl /-?[0-9]*\.?[0-9]*/ ``` בקריאה כאנגלית: ״סימן אופציונלי, ספרות אופציונליות, נקודה עשרונית אופציונלית, ספרות אופציונליות.״ בקריאה כקוד: כל חלק הוא אופציונלי, ולכן התבנית *מתאימה למחרוזת הריקה* — בתחילת כל קלט, לפני שהמנוע אפילו הסתכל. בהחלתה על ״nothing here״ היא מתאימה במיקום 0, לוכדת את המחרוזת הריקה, ומחזירה הצלחה. התיקון הוא לדרוש לפחות ספרה אחת בלפחות צד אחד של הנקודה העשרונית: ```perl /-?[0-9]+(\.[0-9]*)?|-?\.[0-9]+/ ``` שתי חלופות, כל אחת דורשת לפחות ספרה אחת. התבנית מתאימה כעת למה שמחברה התכוון. הלקח מתכלל. תבנית ש *יכולה* להתאים למחרוזת ריקה בדרך כלל *תתאים* למחרוזת ריקה איפשהו. אם ההתאמה חייבת להיות בעלת משמעות, יש לכתוב דרישות שיכפו עליה להיות בעלת משמעות. ## החלפה במבט חטוף החלפת טקסט משתמשת באופרטור `s///`, המקבל תבנית ומחרוזת החלפה: ```perl my $x = "feed the cat"; $x =~ s/cat/dog/; # $x is now "feed the dog" ``` ההחלפה מכוסה לעומק בפרק ייעודי; היא מוזכרת כאן כדי שניתן יהיה לשלבה עם העובדות שלעיל. כמעט כל דבר שחל על תבניות `m//` חל גם בתוך תבניות `s///`. ## לאן ממשיכים מכאן התאמות מילוליות מוליכות באופן מפתיע רחוק, אבל כל regex אמיתי משתמש במחלקות תווים, עוגנים או מכמתים. מחלקות התווים באות אחר כך — הן מאפשרות למיקום אחד בתבנית לקבל כל אחד מכמה תווים. אם קוראים את המדריך לשאלה ספציפית, הפרקים עצמאיים ו־[index](index.md) מפרט את כולם. תבניות שנקראות בסדר אך רצות שעות מכוסות ב־[performance](performance.md) — בספק, התשובה בדרך כלל שם. ## ראו גם - [`m`](../../p5/core/perlfunc/m.md) — מדריך עיון מלא לאופרטור ההתאמה. - [`s`](../../p5/core/perlfunc/s.md) — מדריך עיון מלא להחלפה. - [`qr`](../../p5/core/perlfunc/qr.md) — הידור עצם תבנית. - [`quotemeta`](../../p5/core/perlfunc/quotemeta.md) — escape של מחרוזת לשיבוץ בטוח בתבנית. - פרק [character classes](character-classes.md) — מה בא לאחר התאמה מילולית. - פרק [performance](performance.md) — מה יכול להשתבש.