קבוצות ולכידות#
קיבוץ עושה שני דברים, שקל לבלבל ביניהם: הוא הופך רצף של רכיבי תבנית ליחידה אחת לצורכי כימות וחלופה, והוא שומר את מה שהיחידה התאימה לשימוש מאוחר יותר.
/house(cat|keeper)/; # 'house' followed by 'cat' or 'keeper'
/(ab){3}/; # 'ababab'
/(\d{3})-(\d{4})/; # capture two groups separated by '-'
מעבר לצורת הלכידה הפשוטה (…), Perl מספקת גן חיות קטן של מבנים בסוגריים: קבוצות שאינן לוכדות לקיבוץ נקי, לכידות בעלות שם לתבניות שמתעדות את עצמן, קבוצות אטומיות לבקרת חזרה לאחור, תת־תבניות רקורסיביות עבור מבנים מקוננים, תבניות מותנות להסתעפות לפי לכידות קודמות, ומבנה איפוס הענף לחלופות מקבילות. פרק זה מכסה את כולם.
קבוצות לכידה: $1, $2, …#
כל זוג סוגריים בלא־escape בתבנית פותח קבוצת לכידה. לאחר התאמה מוצלחת, הטקסט שהותאם של הקבוצה ה־n נמצא ב־$n:
if ($time =~ /(\d\d):(\d\d):(\d\d)/) {
my ($hours, $minutes, $seconds) = ($1, $2, $3);
}
בהקשר רשימה, התאמה מחזירה את רשימת המחרוזות הלכודות ישירות:
my ($h, $m, $s) = $time =~ /(\d\d):(\d\d):(\d\d)/;
אם התבנית נכשלת, הרשימה ריקה — אידיום שימושי עבור ״לנתח או לוותר״:
my ($h, $m, $s) = $time =~ /(\d\d):(\d\d):(\d\d)/
or die "not a time: $time";
אין חסם עליון על מספר קבוצות הלכידה. הקבוצות ממוספרות כך שהסוגר השמאלי ביותר הוא קבוצה 1, הבא הוא קבוצה 2, וכן הלאה:
/(ab(cd|ef)((gi)|j))/
1 2 34
$1 לוכד את הקבוצה החיצונית, $2 את הפנימית הראשונה, $3 את הבאה, $4 את הפנימית ביותר.
לכידת מחרוזת ריקה לעומת אי־התאמה כלל#
קבוצת לכידה שלא השתתפה בהתאמה — $n שלה הוא לא־מוגדר. קבוצה שהשתתפה והתאימה למחרוזת ריקה — $n שלה מוגדר ושווה ל־"". ההבחנה חשובה:
"aba" =~ / a (x)* b \g1 a /x; # does NOT match
"aba" =~ / a (x)? b \g1 a /x; # does NOT match
"aba" =~ / a (x*) b \g1 a /x; # matches; $1 = ""
"aba" =~ / a (x?) b \g1 a /x; # matches; $1 = ""
בשני המקרים הראשונים, המכמת מחוץ לקבוצה, ולכן הקבוצה עצמה לעולם לא נסגרה (המנוע התאים אפס איטרציות — לא נכנסו לקבוצה כלל). ההפניה לאחור \g1 אין לה אפוא ערך להשוות אליו והיא נכשלת. בשני המקרים האחרונים, המכמת בתוך הקבוצה, ולכן הקבוצה רצה בדיוק פעם אחת ולכדה מחרוזת ריקה; \g1 מתאים לאותה מחרוזת ריקה במיקום זה.
הלקח: כאשר קבוצה היא אופציונלית, יש להציב את המכמת בתוכה אם רוצים את הסמנטיקה של ״התאמה ריקה נחשבת התאמה״.
יש לבדוק לכידות תמיד עם defined, ולא לאמיתות — לכידה ריקה היא אמת־אך־ריקה תחת סמנטיקת מחרוזות:
if ("x" =~ /(a)?(x)/) {
print "1 is $1\n" if defined $1; # $1 is undef here
print "2 is $2\n" if defined $2;
}
התאמות שנכשלו אינן מאפסות את משתני הלכידה#
אם התאמה נכשלת, $1, $2, … שומרים על ערכיהם הקודמים מן ההתאמה המוצלחת האחרונה באותו תחום. זוהי תכונה: היא מאפשרת לכתוב סדרה של תבניות ספציפיות יותר ולהתייחס לאחר מכן ללכידות של ההתאמה הטובה ביותר.
"foo" =~ /(\w+)/ and "" =~ /(\d+)/; # second fails
print $1; # "foo" — first match's capture survives
זה גם מקור נפוץ לבלבול. יש לבדוק תמיד את ערך ההחזרה של ההתאמה לפני קריאת משתני הלכידה.
קבוצות שאינן לוכדות: (?:…)#
אם נדרש הקיבוץ רק לכימות או לחלופה, ואין רצון בלכידה, יש להשתמש ב־(?:…):
/(?:ab){3}/; # 'ababab', no capture
/(?:\d+\.)*\d+/; # a dotted decimal, no captures at all
קבוצות שאינן לוכדות הן רווח קטן במהירות ורווח גדול יותר בבהירות. הן מאותתות ״הקיבוץ הזה הוא לתחביר, לא לנתונים״. הן גם מונעות מספור מחדש של קבוצות הלכידה שכן חשובות:
# match a number — $1 = whole, $2 = optional exponent value
/([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE]([+-]?\d+))?)/;
ללא העטיפות (?:…), $2, $3, $4 כולם היו נקבעים, וה־$2 המיועד (החזקה) היה זז ל־$5.
הצורה המתוחמת (?flags:…) (למשל (?i:cat), (?xms:…)) מצרפת מתאמים לתבנית הפנימית בלבד, וגם היא אינה לוכדת — ראו פרק modifiers.
גם split נהנה מ־(?:…). split /(?:\s+)/ מפריד לפי רצפי רווח לבן מבלי להכניס את המפרידים לפלט; split /(\s+)/ משאיר אותם במיקומים מתחלפים.
לכידות בעלות שם#
(?<name>…) או (?'name'…) נותן שם לקבוצה. ההתאמה שלה נגישה דרך ההאש %+:
if ("2026-04-23" =~ /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/) {
print "year = $+{year}\n"; # 2026
print "month = $+{month}\n"; # 04
print "day = $+{day}\n"; # 23
}
קבוצות בעלות שם מאכלסות גם את $1, $2, … בסדר השמאל־ימין הרגיל, כך שקוד המשתמש בשתי המוסכמות פועל. בתוך התבנית, יש להפנות לקבוצה בעלת שם באמצעות \k<name> (או כל אחת מצורות הסוגריים/הציטוט להלן):
/(?<quote>["'])(.*?)\k<quote>/; # same quote at start and end
השמות פועלים לפי כללי המזהים של Perl ([_A-Za-z][_A-Za-z0-9]*); הם אינם יכולים להתחיל בספרה ואינם יכולים להכיל מקפים.
אם שתי קבוצות נפרדות חולקות שם, $+{name} מתייחס לקבוצה השמאלית־ביותר־המוגדרת בהתאמה. זה רצוי לעיתים רחוקות מחוץ לאיפוס ענף ((?|…)), שבו שמות משותפים הם אידיומטיים.
(?P<name>…) — תאימות ל־Python/PCRE#
עבור מתכנתים המסבים מן המודול re של Python או מ־PCRE, Perl מקבלת את הכתיבים בסגנון Python:
צורת Python | שקול ב־Perl |
|---|---|
|
|
|
|
|
|
צורות ה־Python פועלות אך אינן אידיומטיות ב־Perl; יש להעדיף את הצורות המקוריות בקוד חדש.
הפניות לאחור#
הפניה לאחור בתבנית דורשת שמיקום מאוחר יותר יתאים לאותו טקסט שלכדה קבוצה קודמת — לא אותה תבנית, אלא אותם תווים בפועל.
צורה | מפנה אל |
|---|---|
| קבוצת הלכידה הראשונה עד התשיעית (צורה ישנה) |
| לכידה ממוספרת; שקול ל־ |
| צורת סוגריים מסולסלים; נדרשת כאשר ספרות היו עוקבות אחרת |
| קבוצת הלכידה האחרונה שנפתחה (יחסי) |
| הקבוצה השנייה־האחרונה שנפתחה |
| לכידה בעלת שם |
| זהה, צורת גרש בודד |
| זהה, צורת סוגריים מסולסלים (מתירה רווחים סובבים) |
| בעלת שם, כתיב חלופי |
דוגמאות:
# Match a three-letter word followed by a space and the same word.
"the the other day" =~ /\b(\w{3})\s\1\b/; # $1 eq 'the'
# Match a four-letter, three-letter, two-letter, or one-letter
# run followed by itself.
/^(\w{1,4})\1$/; # 'beriberi', 'booboo', 'coco', 'mama', 'papa'
\g{…} מול \1 להסרת רב־משמעות#
יש להשתמש ב־\g{…} (או ב־\k<…>) כאשר ספרות או תווים בעלי מראה אוקטלי באים אחרי ההפניה, כדי למנוע רב־משמעות:
/(\d)abc\g{1}23/; # the '1' refers to group 1, '23' is literal
/(\d)abc\123/; # '\123' is octal 0x53 ('S'), not group 1
הכלל של Perl לצורה ה־\N החשופה: \1 עד \9 תמיד מציינים הפניות לאחור. \10, \11, … מציינים הפניה לאחור רק אם מספר כזה של קבוצות לכידה נפתחו קודם לכן בתבנית; אחרת הם תווים מילוליים אוקטליים. בגלל זה \g{...} היא הצורה הבטוחה יותר כשהתבנית נבנית בשרשור.
בשימוש בצורת הסוגריים המסולסלים, רווחים סובבים אופציונליים מותרים — \g{ -1 } ו־\k{ name } תקפים.
הפניות לאחור יחסיות#
\g-1, \g{-1} מתייחסים לקבוצת הלכידה הקודמת מיד; \g{-2} מתייחס לזו שלפניה; וכן הלאה. המרחק נספר לפי סוגריים שנפתחו, כולל בלתי־סגורים. זה חשוב כשמקטע תבנית משובץ בתוך אחר:
my $pair = '([a-z])(\d)\g{-1}\g{-2}'; # a11a, g22g, x33x, ...
# Embed it: outer group shifts numbering by 1, but relative
# backreferences still work:
"code=e99e" =~ /^(\w+)=$pair$/; # matches
ללא הפניות לאחור יחסיות, הדבר היה דורש לדעת כמה קבוצות מקדימות את $pair בכל מקום שיבוץ.
הפניות בעלות שם והפניות יחסיות הופכות תבניות ארוכות לעמידות מול העתק־הדבק.
קבוצות אטומיות: (?>…)#
(?>…) היא קבוצה שאינה לוכדת שתוכנה, ברגע שהותאם, מחויב. המנוע אינו יכול לחזור לאחור לתוך הקבוצה בכישלון — רק מעבר לה כשלמות.
"aaab" =~ /a*ab/; # matches: a* gives back one 'a'
"aaab" =~ /(?>a*)ab/; # does not match: a* takes all, refuses to give
הטיפול המלא נמצא בפרק performance. המבנה מתועד כאן מכיוון שתחבירו הוא קבוצה בסוגריים; מבנית הוא שייך לפרק הלכידות לצד (?:…).
מכמתים קנייניים (*+, ++, ?+, {n,m}+) הם סוכר תחבירי מדויק עבור (?>…) סביב האטום המכומת. הבאים שקולים:
קנייני | צורת קבוצה אטומית |
|---|---|
|
|
|
|
|
|
|
|
גם הכתיב בצורה הארוכה (*atomic:…) מתקבל.
תת־תבניות רקורסיביות#
ביטויי regex של Perl יכולים להפנות חזרה לקבוצת לכידה כאילו הייתה קריאה לתת־שגרה. המבנה מריץ מחדש את התבנית הלכודה במיקום הנוכחי. זה הופך מבנים רקורסיביים אמיתיים לניתנים להתאמה — סוגריים מאוזנים, S־ביטויים, סוגריים מקוננים — מבלי לחרוג מ־DSL ה־regex.
צורה | מבצע רקורסיה ל־ |
|---|---|
| התבנית כולה |
| זהה ל־ |
| קבוצה 1 |
| קבוצה 2 (וכן הלאה) |
| הקבוצה האחרונה שנפתחה (יחסי) |
| הקבוצה הבאה שתיפתח (יחסי קדימה) |
| קבוצה בעלת שם |
| זהה ל־ |
הערה: רקורסיה יחסית סופרת קבוצות לא־סגורות, שלא כמו הפניות לאחור יחסיות. (?-1) תמיד מציין את הקבוצה האחרונה שנפתחה, בין אם נסגרה ובין אם לא.
מתאם של סוגריים מאוזנים:
my $bal = qr/
(?(DEFINE)
(?<paren>
\( # opening paren
(?:
[^()]++ # non-paren run, possessive
| (?&paren) # or a balanced sub-group, recursively
)*+
\) # closing paren
)
)
(?&paren)
/x;
"((a)(b(c)))" =~ /^$bal$/; # matches
הבלוק (?(DEFINE)...) מצהיר על תת־תבנית בעלת שם מבלי להתאים לכלום בעצמו; ה־(?&paren) שאחריו מפעיל את תת־התבנית, וה־(?&paren) הרקורסיבי בתוך הגוף הוא מה שנותן את העומק הבלתי־מוגבל. (?R) לא היה עובד כאן — הוא מבצע רקורסיה לכל התבנית העוטפת, כולל העוגנים ^ ו־$ שמתווספים באתר הקריאה, מה שכופה על כל רמת רקורסיה לדרוש תחילת־ וסוף־מחרוזת.
תבנית רקורסיבית בעלת ניואנסים נוספים: התאמת פונקציה foo(...) שבה הארגומנט עצמו עשוי להכיל סוגריים מאוזנים.
my $re = qr/( # group 1: full function call
foo
( # group 2: parens with content
\(
( # group 3: contents of parens
(?:
(?> [^()]+ ) # non-paren without backtracking
|
(?2) # recurse to group 2
)*
)
\)
)
)/x;
'foo(bar(baz)+baz(bop))' =~ /$re/ and
print "1: $1\n2: $2\n3: $3\n";
# 1: foo(bar(baz)+baz(bop))
# 2: (bar(baz)+baz(bop))
# 3: bar(baz)+baz(bop)
מצב הלכידה בתוך רקורסיה#
כאשר קבוצה מבצעת רקורסיה לעצמה, לכידות שנקבעות בתוך הרקורסיה אינן נראות לקורא לאחר שהרקורסיה חוזרת. לקריאה הרקורסיבית יש מצב לכידה משלה, שמושלך עם החזרה. בגלל זה רוב התבניות הרקורסיביות עוטפות קבוצת לכידה משנית סביב הקריאה הרקורסיבית כשנדרש הטקסט המותאם:
/(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT))
(?(DEFINE)
(?<NAME_PAT>....)
(?<ADDRESS_PAT>....)
)/x
כאן $+{NAME} הוא הלכידה החיצונית; $+{NAME_PAT} אינו מוגדר מכיוון שהוא חי רק בתוך הרקורסיה.
תקרת עומק הרקורסיה מהודרת לתוך המנוע. תבניות המבצעות רקורסיה ללא צריכת קלט נכשלות מיד במקום לרוץ לנצח — המנוע מזהה את המעגל.
בלוקי (DEFINE)#
הבלוק (?(DEFINE)…) מחזיק תת־תבניות בעלות שם שאינן רצות בפני עצמן — הן מופעלות רק דרך (?&NAME). כך כותבים regex שנראה כמו דקדוק קטן:
my $email = qr/
\A (?&LOCAL) @ (?&DOMAIN) \z
(?(DEFINE)
(?<LOCAL> [\w.+-]+ )
(?<DOMAIN> (?&LABEL) (?: \. (?&LABEL) )+ )
(?<LABEL> [a-zA-Z0-9] (?: [a-zA-Z0-9-]* [a-zA-Z0-9] )? )
)
/x;
בלוק ה־DEFINE בסוף מחזיק את תת־התבניות בעלות השם במקום אחד; ראש התבנית נקרא כמפרט נקי.
שתי אזהרות:
תת־תבניות בבלוק DEFINE נספרות לטובת המספור המוחלט והיחסי של קבוצות הלכידה בתבנית העוטפת. יש לתת שם לכל דבר ב־DEFINE כדי שלא יהיה צורך לספור.
האופטימייזר פחות אפקטיבי על תבניות בסגנון DEFINE לעומת הצורה השורתית השקולה. הן רצות, אך לא תמיד במהירות העליונה.
תבניות מותנות: (?(cond)yes|no)#
תבנית מותנית בוחרת בין שתי תת־תבניות על־סמך בדיקת זמן ריצה:
(?(N)YES|NO)— מתאים ל־YES אם קבוצה N התאימה למשהו, אחרת NO.(?(<NAME>)YES|NO)— זהה, אך לפי שם.(?(?=LOOK)YES|NO)— מתאים ל־YES אם ה־lookahead מצליח.(?(?{CODE})YES|NO)— מתאים ל־YES אם בלוק הקוד מחזיר אמת.(?(R)YES|NO)— מתאים ל־YES אם נמצאים כעת בתוך רקורסיה.(?(R1)YES|NO)— מתאים ל־YES אם מבצעים רקורסיה דרך קבוצה 1.(?(R&NAME)YES|NO)— מתאים ל־YES אם מבצעים רקורסיה דרך קבוצה בעלת שם.
ענף ה־NO הוא אופציונלי; היעדר NO מטופל כ״תמיד מתאים״.
דוגמה מעובדת: טקסט בציטוט אופציונלי. אם הקלט פותח ב־(, יש לדרוש ) סוגר. אחרת, אין לאפשר סוגריים:
m{ ( \( )? # optional opening paren, group 1
[^()]+ # body (no parens)
(?(1) \) ) # if group 1 matched, require closing paren
}x;
ללא תבניות מותנות, היה דרוש לכך חלופה המכסה את שתי הצורות; הגרסה המותנית חושפת את הכוונה.
דוגמה מעובדת: דקדוק מאוזן עם רקורסיה בעלת שם. שימושי בתוך בלוק DEFINE לאימות תלוי־הקשר:
qr/
(?<expr>
(?<atom> [a-z]+ | \( (?&expr) \) )
(?: \s* [+*] \s* (?&atom) )*
)
/x
התניות הן החלק של regex הדומה ביותר לשפת תכנות אמיתית; יש להישען עליהן כאשר חלופה של צורות בלעדיות זו לזו תהיה מסורבלת.
איפוס ענף: (?|…)#
בתוך (?|…), כל ענף חלופי מתחיל למספר את לכידותיו באותה משבצת. לאחר הקבוצה, המספור מתחדש אחת מעבר למקסימום בכל הענפים. הטיפול המלא בפרק alternation; ההשלכות על מספור הלכידות שייכות כאן.
# Before ---------------branch-reset----------- after
/ ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x
# 1 2 2 3 2 3 4
לאחר שהתבנית הזו מתאימה:
$1הוא תמיד ה־aהמוביל.$2הואy,(p q r), אוtבהתאם לענף.$3הוא undef מענף 1,qמענף 2,vמענף 3.$4הוא ה־zהסופי.
בשימוש בלכידות בעלות שם בתוך (?|…), יש להשתמש באותם שמות באותו סדר בכל ענף:
/(?| (?<a> x ) (?<b> y )
| (?<a> z ) (?<b> w )) /x;
ערבוב שמות בין ענפים עובד (Perl פותרת לשם השמאלי־ביותר־המוגדר) אך מפיק תוצאות מפתיעות: כל שם מפנה לאותה משבצת, ולכן $+{a} ו־$+{b} עשויים להיות בעלי אותו ערך בענפים שונים.
מערכי מיקום: @- ו־@+#
לאחר התאמה מוצלחת, @- ו־@+ מחזיקים את היסטים ההתחלה והסוף של ההתאמה כולה ושל כל קבוצת לכידה:
$-[0],$+[0]— היסטים של ההתאמה כולה.$-[n],$+[n]— היסטים של הלכידה ה־n, או undef אם הקבוצה לא השתתפה.
my $s = "Mmm...donut, thought Homer";
if ($s =~ /^(Mmm|Yech)\.\.\.(donut|peas)/) {
for my $i (1 .. $#-) {
printf "Match %d: %s at (%d,%d)\n",
$i,
substr($s, $-[$i], $+[$i] - $-[$i]),
$-[$i], $+[$i];
}
}
# Match 1: Mmm at (0,3)
# Match 2: donut at (6,11)
היסטים לעיתים קלים יותר ממחרוזות־משנה כאשר נדרש לשנות את המחרוזת המקורית במיקום ההתאמה.
@{^CAPTURE} — לכידות כמערך#
Perl חושפת את כל הלכידות הממוספרות כמערך יחיד @{^CAPTURE}, אינדוקס מאפס (כך שאינדקס 0 הוא $1, אינדקס 1 הוא $2, …):
$string =~ /$pattern/ and my @captured = @{^CAPTURE};
זה נוח כאשר מספר הלכידות הוא משתנה או לא־ידוע — קוד שלוקח לכידות מתבנית שסופקה על־ידי המשתמש כבר אינו צריך לספור ( כדי לדעת כמה $1/$2/… לקרוא.
אינדוקס דורש את צורת הסוגריים המסולסלים המתוחמת:
print "${^CAPTURE[0]}"; # equivalent to $1
%{^CAPTURE_ALL} ו־%{^CAPTURE_NAMES} קיימים להתבוננות בלכידות בעלות שם — ראו perlvar.
טרום־התאמה, התאמה, פוסט־התאמה#
Perl קובעת שלושה סקלרים מיוחדים אחרי כל התאמה שחושפים את הטקסט הסובב:
$`— כל מה שלפני ההתאמה (ה־pre-match).$&— ההתאמה עצמה.$'— כל מה שאחרי ההתאמה (ה־post-match).
"the cat caught the mouse" =~ /cat/;
# $` = 'the '
# $& = 'cat'
# $' = ' caught the mouse'
הוריאנטים בעלי השם ${^PREMATCH}, ${^MATCH}, ${^POSTMATCH} שקולים. שתי הצורות הן ללא־עלות; יש להשתמש באחת שנקראת טוב יותר.
$+ ו־$^N#
$+ מחזיק את ההתאמה של קבוצת הלכידה בעלת המספר הגבוה ביותר שהצליחה.
$^N מחזיק את ההתאמה של קבוצת הלכידה האחרונה שנסגרה — ה־) הימני ביותר שהושלם. זה בדיוק מה שצריך בתוך בלוק קוד (?{…}) כדי לגשת ללכידה האחרונה ללא ספירת סוגריים:
$_ = "The brown fox jumps over the lazy dog";
/the (\S+)(?{ $color = $^N }) (\S+)(?{ $animal = $^N })/i;
print "color = $color, animal = $animal\n";
# color = brown, animal = fox
ראו פרק performance לסיפור המלא של קוד מוטמע.
מקסום תת־ביטוי ב־POSIX — מה שמנועים אחרים עושים#
חלק מהמנועים (כל NFA תואם POSIX, בתוספת מימושי מנועים שתוכננו לחקות POSIX, בתוספת רוב היברידי DFA) פועלים לפי כלל אחר לאיזו התאמה מנצחת כשאפשריות מספר כאלה: הארוכה־השמאלית־ביותר, בהגבלה שכל תת־ביטוי לוכד את מחרוזת־המשנה הארוכה ביותר שביכולתו.
עבור התבנית (to|top)(o|polo)?(gical|o?logical) מול topological:
Perl (ו־PCRE2, וכל NFA מסורתי) מנסה חלופות משמאל לימין.
(to|top)מתאים ל־to; המנוע ממשיך.(o|polo)מתאים ל־o; ממשיך.(gical|o?logical)מתאים ל־logical. בוצע.סמנטיקת POSIX דורשת שההתאמה הכוללת תהיה הארוכה ביותר, ובין התאמות באורך שווה, שהלכידה של כל קבוצה בודדת תהיה הארוכה ביותר. התוצאה היא
toppological, כאשר כל לכידה ברוחבה המרבי.
מנועים מודרניים בעצם אינם משתמשים בסמנטיקת POSIX-NFA לעולם, אך כלים מסוימים מבוססי־DFA (grep, awk) מקרבים אותה. בפרק cross-engine הטבלה המלאה.
השוואה בין מנועים: לכידות והפניות לאחור#
זוהי התכונה שבה המנועים מתבדלים זה מזה במידה הרבה ביותר. הטבלה המלאה בפרק cross-engine; השורות הרלוונטיות חולצו:
תכונה | Perl 5.42 | PCRE2 | Emacs | POSIX BRE | POSIX ERE | RE2/Go |
|---|---|---|---|---|---|---|
לכידות ממוספרות | כן | כן | כן | כן | מחמיר לא, GNU כן | כן (ללא הפניות לאחור) |
הפניות לאחור בתבנית ( | כן | כן | כן | כן ( | מחמיר לא | לא |
לכידות בעלות שם | כן | כן | לא | לא | לא | כן |
איפוס ענף | כן | כן | לא | לא | לא | לא |
מערך | כן | לא | לא | לא | לא | לא (API שונה) |
תת־תבניות רקורסיביות | כן | כן | לא | לא | לא | לא |
תבניות מותנות | כן | כן | לא | לא | לא | לא |
המסקנה החשובה ביותר: regexp של RE2 / Go אינו תומך בהפניות לאחור כלל. זה לא היסח דעת; זה המחיר ש־RE2 משלם עבור התאמה מובטחת בזמן ליניארי. תבניות הזקוקות להפניות לאחור אינן שפות רגולריות ואינן ניתנות להתאמה על־ידי DFA בזמן ליניארי.
בעת הסבת ביטויי regex של Perl לשירות Go, יש לבדוק אותם להפניות לאחור לפני הנחה שההמרה מכנית. תבניות כמו /(?<a>\w+) and \k<a>/ פשוט אינן ניתנות לביטוי ב־RE2.
ראו גם#
פרק alternation — איפוס ענף וההשלכות של מספור החלופות של
(?|…).פרק performance — קבוצות אטומיות, תבניות רקורסיביות בדוגמאות מעובדות, קוד מוטמע.
פרק modifiers —
/nלדיכוי כל הלכידות.perlvar—%+,%-,$&,$^N,@{^CAPTURE}וחבריהם.