# החלפה `s///` הוא אופרטור החיפוש־וההחלפה. צורתו הכללית היא ```default $target =~ s/pattern/replacement/modifiers; ``` הוא מוצא את המיקום הראשון שבו *תבנית* מתאימה ב *מטרה*, מחליף את ההתאמה ב *החלפה*, ומחזיר את מספר ההחלפות שבוצעו. עם `/g`, הוא עושה זאת עבור כל התאמה שאינה חופפת. ```perl my $x = "Time to feed the cat!"; $x =~ s/cat/hacker/; # $x is now "Time to feed the hacker!" ``` אם התבנית אינה מתאימה, המטרה נותרת ללא שינוי ו־`s///` מחזיר ערך שקר. ## פעולה על `$_` כמו `m//`, `s///` מוגדר כברירת מחדל ל־`$_` כאשר לא ניתן `=~`: ```perl for (@lines) { s/\s+$//; # trim trailing whitespace from each line } ``` ## ספירת החלפות ערך ההחזרה של `s///` בהקשר סקלרי הוא מספר ההחלפות: ```perl my $count = ($text =~ s/\btodo\b/done/gi); print "cleared $count todos\n"; ``` בהקשר בוליאני, אפס פירושו אין התאמה. ## מחרוזת ההחלפה ההחלפה היא מחרוזת במרכאות כפולות, כך שמשתנים ורצפי בריחה משובצים בה: ```perl my $suffix = ".bak"; $file =~ s/$/$suffix/; # append .bak to the name $x =~ s/\t/ /g; # each tab becomes four spaces ``` בתוך ההחלפה, `$1`, `$2`, `$&`, `$+` וחבריהם מתייחסים למה שההתאמה ה *נוכחית* זה עתה לכדה: ```perl my $y = "'quoted words'"; $y =~ s/^'(.*)'$/$1/; # strip surrounding single quotes # $y is now "quoted words" ``` לכידות בשם פועלות באותו אופן באמצעות `$+{name}`: ```perl "2026-04-23" =~ s/(?\d{4})-(?\d{2})-(?\d{2})/$+{d}\/$+{m}\/$+{y}/; # result: "23/04/2026" ``` ## מילוט בהחלפה ההחלפה מפורשת כמחרוזת במרכאות כפולות, ולכן כללי המרכאות הכפולות חלים *עליה*, באופן עצמאי מהתבנית. תווים מטא כמו `*`, `+`, `?`, `$` שומרים על משמעותם במרכאות כפולות — רק `$` ו־`@` מפעילים שיבוץ: ```perl $x =~ s/(\w+)/[$1]/g; # wrap every word in brackets $x =~ s/\$/USD/g; # replace literal '$' with 'USD' ``` Backslash escape sequences in the replacement follow the double-quote rules — `\t`, `\n`, `\x{…}` all work. The special case-modification escapes `\l`, `\u`, `\L`, `\U`, `\E`, `\Q` apply in the replacement too: ```perl $x =~ s/(\w+)/\u$1/g; # capitalise the first letter of each word $x =~ s/(\w+)/\U$1\E/g; # uppercase whole word ``` ### אזהרה: `\1` מול `$1` בהחלפה ניב שעבר תהליך התאזרחות ארוך: כתיבת `\1`, `\2`, … בהחלפה במשמעות ״הלכידה הראשונה״, ״הלכידה השנייה״: ```perl $pattern =~ s/(\W)/\\\1/g; # works, but is a trap ``` Perl מקבלת `\1` עד `\9` בהחלפה של `s///` לצורכי תאימות היסטורית עם `sed`. **יש להשתמש ב־`$1` עד `$9` במקום.** הסיבה היא שההחלפה היא מחרוזת במרכאות כפולות, שבה `\1` *בדרך כלל* פירושו תו control-A. כלל המקרה המיוחד של אופרטור ההחלפה מאלתר את הפירוש של המרכאות הכפולות כך שיהיה ״לכידה ראשונה״, אך הקצוות חדים. באופן ספציפי: שילוב של `\1` עם `/e` מחזיר את המשמעות של מרכאות כפולות. תחת `/e`, ההחלפה היא *קוד Perl*; בקוד Perl, `"\1"` הוא control-A: ```perl s/(\d+)/ \1 + 1 /eg; # warning: \1 better written as $1 ``` קצה חד שני: `\1` ואחריו תווי ספרות הוא דו־משמעי. `\1000` יכול להתפרש כ״לכידה ראשונה, ואז `000` מילולי״, או כ״0x40 אוקטלי (`@`) — ולא ניתן ליישב את הדו־משמעות באמצעות כתיבת `\{1}000`״: ```perl s/(\d+)/\1000/; # ambiguous, best avoided s/(\d+)/${1}000/; # unambiguous ``` הכלל לקוד חדש: **תמיד יש להשתמש ב־`$1` בהחלפה, לעולם לא ב־`\1`**. הצורה `\1` שרדה כירושה היסטורית, ואינה מומלצת. ## `/g` — החלפת הכל ללא `/g`, `s///` מחליף רק את ההתאמה הראשונה. עם `/g`, הוא מחליף כל התאמה שאינה חופפת משמאל לימין: ```perl my $x = "I batted 4 for 4"; $x =~ s/4/four/; # "I batted four for 4" $x = "I batted 4 for 4"; $x =~ s/4/four/g; # "I batted four for four" ``` `/g` בהחלפה אינו קשור ל־`/g` בהתאמה. כאן הוא פשוט אומר ״עשה זאת שוב ושוב עד שהתבנית מפסיקה להתאים״. ### התאמות אורך אפס ו־`s///g` תבנית היכולה להתאים את המחרוזת הריקה מציבה בעיה תחת `/g`: כל מיקום היה מתאים שוב לעולם. Perl שוברת את הלולאה הזו עם כלל ספציפי: **לאחר התאמת אורך אפס, הניסיון הבא באותו מיקום אסור להיות גם הוא באורך אפס**. המנוע לוקח במקום זאת את ההתאמה הטובה ביותר השנייה. ההדגמה הנקייה ביותר: ```perl $_ = 'bar'; s/\w??/<$&>/g; # Result: <><><><> ``` ה־`\w??` הלא־חמדן מעדיף את ההתאמה הריקה. לאחר ייצור אחת, האיטרציה הבאה אסורה להיות גם היא באורך אפס, לכן המנוע לוקח את ההתאמה הטובה ביותר השנייה — תו `\w` בודד. ואז עוד התאמה ריקה, ואז עוד תו, וכן הלאה, לסירוגין עד שהמחרוזת נצרכת. התבנית: התאמות אורך אפס מתחלפות עם התאמות של תו אחד, וההחלפה אינה נכנסת ללולאה אינסופית. מסקנה שימושית: `s/(\d{3})/$1,/g` אינו מכניס פסיק אחרי כל קבוצה של שלוש ספרות *באופן נכון* — הוא מכניס אחרי השלוש הראשונות משמאל, ואז השלוש הבאות, ללא קשר למיקום שבו רציתם את הפסיקים. כדי להכניס מפרידי אלפים, יש להתאים מימין או להשתמש ב־`1 while`: ```perl my $n = "1234567"; 1 while $n =~ s/^(\d+)(\d{3})/$1,$2/; # n is now "1,234,567" ``` ה־`1 while` חוזר עד שההחלפה מחזירה שקר (אין יותר התאמות), וזה בדיוק מה שרוצים עבור ״כל מיקום, לאחר התייצבות״. ## `/e` — הערכת ההחלפה תחת `/e`, ההחלפה היא קוד Perl, ולא מחרוזת. הקוד רץ עבור כל התאמה וערך ההחזרה שלו מחליף את ההתאמה. ```perl my $x = "numbers: 1 2 3 4"; $x =~ s/(\d+)/$1 * 2/ge; # "numbers: 2 4 6 8" ``` משתני ההתאמה `$1`, `$2`, … גלויים בתוך בלוק הקוד. שימושים מעשיים: ```perl # Uppercase the first letter of every sentence. $text =~ s/(^|\.\s+)(\w)/$1\U$2/g; # Hex-encode non-ASCII bytes. $bytes =~ s/([\x80-\xff])/sprintf "\\x%02x", ord $1/ge; # Apply a lookup table. my %subst = (red => 0xff0000, green => 0x00ff00, blue => 0x0000ff); $css =~ s/\b(red|green|blue)\b/sprintf "#%06x", $subst{$1}/ge; ``` ### `/ee` — הערכה כפולה `/ee` מעריך *פעמיים* — תחילה כקוד, ואז התוצאה עצמה מוערכת כ־Perl. המקרה לשימוש הוא חיפוש דינמי של משתנה לפי שם: ```perl our $greeting = "hello"; my $s = "greeting"; $s =~ s/(\w+)/"\$$1"/ee; # first: '$greeting'; second: 'hello' # $s is now "hello" ``` ההחלפה היא ביטוי Perl — המרכאות הכפולות המפורשות גורמות לו להפיק את ה *מחרוזת* `"$greeting"`. ה־`e` הראשון מעריך את הביטוי הזה למחרוזת `$greeting`. ה־`e` השני מתייחס למחרוזת הזו כ־Perl, מחפש את המשתנה `$greeting` ומפיק `hello`. מיקום ההתאמה מוחלף בערך `hello`. המקרה לשימוש מצומצם וההשלכות האבטחתיות משמעותיות: כל קלט המגיע להחלפת `/ee` מורץ למעשה כ־Perl. יש להתייחס ל־`/ee` כמו אל `eval` — לעולם לא על נתונים שסופקו על ידי משתמש. ## `/r` — החלפה לא־הרסנית `/r` מחזיר את המחרוזת החדשה במקום לשנות את המטרה. המטרה אינה נוגעת: ```perl my $orig = "I like dogs"; my $new = $orig =~ s/dogs/cats/r; # $orig is still "I like dogs" # $new is "I like cats" ``` אם התבנית אינה מתאימה, `/r` מחזיר את המחרוזת המקורית ללא שינוי: ```perl my $x = "I like dogs"; my $y = $x =~ s/elephants/cougars/r; # $y eq "I like dogs" ``` הרווח הגדול הוא בשרשור: ```perl my $slug = $title =~ s/[^\w\s-]//gr # drop punctuation =~ s/\s+/-/gr # collapse spaces to dash =~ s/--+/-/gr; # collapse runs of dashes ``` כל חץ מחזיר מחרוזת חדשה, שאותה מקבל ה־`s///r` הבא. ## `\K` בהחלפה `\K` (מכוסה בפירוט בפרק [anchors and assertions](anchors-and-assertions.md)) זורח בהחלפה. התבנית מתאימה קידומת שמבססת הקשר, ואז `\K` מוציא את הקידומת ממטרת ההחלפה: ```perl # Without \K — the prefix has to be re-output: $_ =~ s/(foo)bar/$1/g; # With \K — the prefix is matched but not part of $&: $_ =~ s/foo\Kbar//g; ``` שתיהן מחליפות `foobar` ב־`foo`. צורת ה־`\K` נקייה יותר: אין צורך בלכידה, ותבנית ההחלפה קצרה ומהירה יותר. `\K` עובד באופן דומה בכל החלפה שבה קידומת קבועה צריכה להתאים אך לא להיות מוחלפת. זהו התאום בצד ההחלפה של הצצה לאחור. ## החלפה ו־`pos()` `s///g` מוצלח מקדם את `pos($string)` מעבר לכל התאמה. התאמת אורך אפס מקדמת את `pos` באחד כדי לשבור את הלולאה. לאחר ההחלפה, `pos` מאופס. אינטראקציה עדינה: `s///g` לא יסרוק מחדש אזור שזה עתה הותאם. לאחר כל החלפה מוצלחת מיקום ההתאמה מתקדם מעבר לטקסט ה *מותאם* — אורך ההחלפה אינו משנה. לכן: ```perl my $x = "aaa"; $x =~ s/a/AA/g; # $x is "AAAAAA" — three a's, each replaced with AA # It is NOT an infinite loop: pos() moves past each matched 'a', # so the just-inserted 'A's are never re-scanned. ``` זה לעיתים מפתיע עבור החלפות שההחלפה שלהן מכילה תווים שהתבנית גם הייתה מתאימה. הכלל הוא ״התקדם מעבר לטקסט המותאם, לעולם אל תסרוק אותו מחדש״. ## תוחמים חלופיים שני החצאים של `s///` יכולים להשתמש בסוגריים מותאמים; אין צורך שהתוחמים יהיו זהים: ```perl s{pattern}{replacement}g; sg; s[pattern][replacement]g; s(pattern)[replacement]g; # legal, but avoid mixing for clarity ``` כל תו פיסוק שניתן להדפסה עובד בצורה של תו בודד: ```perl s!/usr/local/!/opt/!g; s#pattern#replacement#; ``` שימושי כאשר התבנית או ההחלפה מכילות `/`. ## החלפה במרכאות בודדות `s'pattern'replacement'` מתייחס לשני החצאים כמרכאות בודדות — ללא שיבוץ משתנים, ללא רצפי בריחה עם לוכסן הפוך פרט ל־`\'` ול־`\\`: ```perl s'@users'@admins'g; # literal '@users' becomes literal '@admins' ``` נדרש לעיתים רחוקות; מוזכר כאן לשם השלמות. ## שילוב עם `/m`, `/s`, `/x` מתאמי החלפה מתחברים עם מתאמי התאמה, כך שניתן לקבל את ארגז הכלים המלא: ```perl # Trim each line. $x =~ s/^\s+|\s+$//mg; # Collapse blank lines. $x =~ s/\n{2,}/\n\n/g; # Replace C-style comments across newlines. $src =~ s{/\*.*?\*/}{}gs; # /s lets . cross newlines ``` עם `/x` התבנית קריאה, עם `/s` היא משתרעת על מעברי שורה, עם `/g` היא חוזרת. ## דוגמה אמיתית הופכים בלוק של טקסט אנגלי ל־slug — אותיות קטנות, מקפים במקום רווחים, הסרת תווים שאינם אותיות, כיווץ וגזירה: ```perl sub slug { my ($s) = @_; return lc($s) =~ s/[^\w\s-]//gr # remove punctuation =~ s/\s+/-/gr # spaces to hyphens =~ s/-+/-/gr # collapse hyphens =~ s/^-|-$//gr; # trim leading/trailing hyphens } print slug("Hello, World! -- Regex Tutorial"); # prints: hello-world-regex-tutorial ``` ## הניסוח של פרידל — ״כל דבר שאינו נדרש ייחשב תמיד כמוצלח״ חלקי תבנית אופציונליים יצליחו תמיד אם הם יכולים להתאים לכלום. זה חל בתוך החלפה באותו תוקף כמו בהתאמה: ```perl my $x = "no horizontal rule here"; $x =~ s/-*/
/; # Result: "
no horizontal rule here" ``` התבנית `-*` מתאימה אפס או יותר מקפים — ואפס תמיד זמין, בתחילת המחרוזת. `
` מוכנס במיקום 0. התבנית הצליחה לפי הגדרת המנוע; היא נכשלה לפי שלכם. התיקון הוא לדרוש לפחות מקף אחד: ```perl $x =~ s/-+/
/; # no match; $x unchanged ``` הסיסמה: **תמיד יש לשקול מה יקרה אם אין התאמה**. חלקים אופציונליים אינם חינם; הם תמיד מצליחים על ידי התאמה לכלום באיזשהו מקום. ## דברים שנראים כמו החלפה אך אינם `tr///` (נכתב גם `y///`) מבצע תעתיק תו־תו, לא החלפה של ביטוי רגולרי. הוא מקבל שתי רשימות של תווים; כל הופעה של התו ה־n ברשימה הראשונה הופכת לתו ה־n ברשימה השנייה. תכונות של ביטוי רגולרי אינן חלות: ```perl my $x = "Hello"; $x =~ tr/A-Za-z/a-zA-Z/; # swap case (my $hex = $bytes) =~ tr/\x00-\xff//d; # delete all bytes — pointless ``` `tr///` מהיר מ־`s///` עבור עבודה ברמת התו מכיוון שהוא אינו מנוע ביטויים רגולריים. ראו [`tr`](../../p5/core/perlfunc/tr.md) לסמנטיקה מלאה. ## ראו גם - [`s`](../../p5/core/perlfunc/s.md) — הפניה לאופרטור ההחלפה. - [`tr`](../../p5/core/perlfunc/tr.md) — תעתיק תווים; אינו החלפה אך מבולבל איתה לעיתים קרובות. - [`quotemeta`](../../p5/core/perlfunc/quotemeta.md) — מילוט מחרוזת לשיבוץ בטוח בתבנית. - פרק [modifiers](modifiers.md) — `/g`, `/e`, `/r`, `/ee`, וכיצד הם מתקשרים זה לזה. - פרק [anchors and assertions](anchors-and-assertions.md) — `\K` עבור ״התאם קידומת זו אך אל תחליף אותה״. - פרק [performance](performance.md) — סיום התאמת אורך אפס של `s///g` בפירוט.