GoGPT Best VPN GoSearch

סמל OnWorks

perlretut - מקוון בענן

הפעל את perlretut בספק אירוח בחינם של OnWorks על אובונטו מקוון, פדורה מקוון, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

זוהי הפקודה perlretut שניתן להריץ בספק האירוח החינמי של OnWorks באמצעות אחת מתחנות העבודה המקוונות המרובות שלנו, כגון Ubuntu Online, Fedora Online, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

תָכְנִית:

שֵׁם


perlretut - מדריך לביטויים רגולריים של Perl

תיאור


דף זה מספק הדרכה בסיסית על הבנה, יצירה ושימוש רגיל
ביטויים בפרל. זה משמש כהשלמה לדף ההתייחסות באופן קבוע
ביטויים perlre. ביטויים רגולריים הם חלק בלתי נפרד מה-"m//", "s///", "qr//"
אופרטורים "פיצול" ולכן המדריך הזה גם חופף ל-"Regexp Quote-Like
מפעילים" ב-perlop ו-"פיצול" ב-perlfunc.

Perl ידועה בשל מצוינות בעיבוד טקסט, וביטויים רגולריים הם אחד
מהגורמים הגדולים מאחורי התהילה הזו. ביטויים רגולריים של Perl מציגים יעילות ו
גמישות לא ידועה ברוב שפות המחשב האחרות. שליטה אפילו ביסודות של
ביטויים רגילים יאפשרו לך לתפעל טקסט בקלות מפתיעה.

מהו ביטוי רגולרי? ביטוי רגולרי הוא פשוט מחרוזת שמתארת ​​א
תבנית. דפוסים נמצאים בשימוש נפוץ בימינו; דוגמאות הן הדפוסים שהוקלדו לתוך a
מנוע חיפוש למציאת דפי אינטרנט והדפוסים המשמשים לרשימת קבצים בספרייה, למשל,
"ls *.txt" או "dir *.*". ב-Perl, נעשה שימוש בדפוסים המתוארים על ידי ביטויים רגולריים
כדי לחפש מחרוזות, לחלץ חלקים רצויים של מחרוזות, ולבצע חיפוש והחלפה
פעולות.

לביטויים רגילים יש את המוניטין הבלתי ראוי של מופשטים וקשים לביצוע
מבין. ביטויים רגולריים נבנים באמצעות מושגים פשוטים כמו תנאים
ולולאות ואינן קשות יותר להבנה מהתנאי ה"אם" המקבילים
ו-"while" לולאות בשפת Perl עצמה. למעשה, האתגר העיקרי בלמידה
ביטויים רגולריים זה רק להתרגל לסימון התמציתי המשמש לביטוי אלה
מושגים.

מדריך זה משטח את עקומת הלמידה על ידי דיון במושגי ביטוי רגולרי, יחד
עם הסימון שלהם, אחד בכל פעם ועם דוגמאות רבות. החלק הראשון של ההדרכה
יתקדם מחיפושי המילים הפשוטים ביותר למושגי הביטוי הרגולרי הבסיסיים.
אם תשלוט בחלק הראשון, יהיו לך את כל הכלים הדרושים כדי לפתור כ-98% של
הצרכים שלך. החלק השני של המדריך מיועד למי שנוח עם היסודות ו
רעב לעוד כלים חשמליים. הוא דן באופרטורים המתקדמים יותר של ביטוי רגולרי
ומציגה את החידושים החדשים ביותר.

הערה: כדי לחסוך זמן, 'ביטוי רגולרי' מקוצר לעתים קרובות כ-regexp או regex.
Regexp הוא קיצור טבעי יותר מאשר Regex, אך קשה יותר לבטא אותו. הפרל
תיעוד התרמיל מחולק באופן שווה ב-regexp לעומת regex; בפרל יש יותר מדרך אחת
לקצר את זה. נשתמש ב- regexp במדריך זה.

חדש בגרסה 5.22, "use re 'strict'" מחיל כללים מחמירים יותר מאשר אחרת בעת ההידור
דפוסי ביטוי רגולרי. זה יכול למצוא דברים שלמרות שהם חוקיים, אולי לא מה שאתה
התכוון.

חלק 1: השמיים יסודות


פָּשׁוּט מילה תואם
הביטוי הרגולרי הפשוט ביותר הוא פשוט מילה, או באופן כללי יותר, מחרוזת של תווים. ביטוי מחודש
המורכב ממילה תואם לכל מחרוזת המכילה את המילה הזו:

"שלום עולם" =~ /עולם/; # התאמות

על מה הצהרת פרל הזו? "Hello World" היא מחרוזת פשוטה במירכאות כפולות.
"עולם" הוא הביטוי הרגולרי וה-"//" המקיף את "/World/" אומר לפרל לחפש
מחרוזת לגפרור. האופרטור "=~" משייך את המחרוזת ל-Regexp match and
מייצר ערך אמיתי אם הביטוי הרגולרי תואם, או false אם הביטוי הרגולרי לא התאים. בשלנו
במקרה, "עולם" תואם למילה השנייה ב-"Hello World", כך שהביטוי נכון.
ביטויים כמו זה שימושיים בתנאים תנאים:

if ("שלום עולם" =~ /עולם/) {
הדפס "זה תואם\n";
}
אחר {
הדפס "זה לא תואם\n";
}

ישנן וריאציות שימושיות לנושא זה. ניתן להפוך את תחושת ההתאמה על ידי
באמצעות האופרטור "!~":

if ("שלום עולם" !~ /World/) {
הדפס "זה לא תואם\n";
}
אחר {
הדפס "זה תואם\n";
}

ניתן להחליף את המחרוזת המילולית ב- regexp במשתנה:

$greeting = "עולם";
if ("שלום עולם" =~ /$greeting/) {
הדפס "זה תואם\n";
}
אחר {
הדפס "זה לא תואם\n";
}

אם אתה תואם למשתנה ברירת המחדל המיוחד $_, החלק "$_ =~" יכול להיות
הושמט:

$_ = "שלום עולם";
if (/עולם/) {
הדפס "זה תואם\n";
}
אחר {
הדפס "זה לא תואם\n";
}

ולבסוף, ניתן לשנות את תווי ברירת המחדל של "//" עבור התאמה לשרירותי
תוחמים על ידי הצבת 'm' בחזית:

"שלום עולם" =~ m!World!; # התאמות, מופרדות על ידי '!'
"שלום עולם" =~ m{עולם}; # התאמות, שימו לב ל-'{}' התואם
"/usr/bin/perl" =~ m"/perl"; # התאמות אחרי '/ usr / bin',
# '/' הופך ל-char רגיל

"/World/", "m!World!" ו-"m{World}" כולם מייצגים את אותו הדבר. כאשר, למשל, הציטוט
(""") משמש כמפריד, הלוכסן הקדמי '/' הופך לתו רגיל ויכול
לשמש בביטוי הרגולרי הזה ללא בעיות.

בואו נשקול כיצד ביטויים רגועים שונים יתאימו ל-"Hello World":

"שלום עולם" =~ /עולם/; # לא תואם
"שלום עולם" =~ /o W/; # התאמות
"שלום עולם" =~ /oW/; # לא תואם
"שלום עולם" =~ /עולם /; # לא תואם

"העולם" הראשון של הביטוי הרגולרי אינו תואם כי הביטויים הרגולריים הם תלויי רישיות. השני
ביטוי regexp מתאים מכיוון שמחרוזת המשנה 'o W' מופיעה במחרוזת "Hello World". החלל
הדמות ' ' מטופלת כמו כל דמות אחרת בביטוי רגולרי ויש צורך להתאים אותה
מקרה זה. היעדר תו רווח הוא הסיבה שהביטוי הרגולרי השלישי 'oW' אינו עושה זאת
התאמה. הביטוי הרגולרי הרביעי 'World' אינו תואם כי יש רווח בסוף
הביטוי הרגולרי, אבל לא בסוף המחרוזת. הלקח כאן הוא שהביטויים הרגולריים חייבים להתאים
חלק מהמחרוזת בדיוק על מנת שהמשפט יהיה נכון.

אם ביטוי רגולרי מתאים ביותר ממקום אחד במחרוזת, Perl תמיד יתאים ב-
הנקודה המוקדמת ביותר האפשרית במחרוזת:

"שלום עולם" =~ /o/; # תואם את 'o' ב'שלום'
"הכובע הזה אדום" =~ /כובע/; # תואם את 'כובע' ב'זה'

לגבי התאמת דמויות, יש עוד כמה נקודות שאתה צריך לדעת עליהן.
קודם כל, לא ניתן להשתמש בכל התווים 'כמות שהם' בהתאמה. כמה דמויות, שנקרא
מטא-דמויות, שמורות לשימוש בתווי ביטוי רגולי. המטא-תווים הם

{}[]()^$.|*+?\

המשמעות של כל אחד מאלה תוסבר בהמשך המדריך, אבל עבור
כעת, חשוב רק לדעת שניתן להתאים תו מטא על ידי הצבת a
קו נטוי לפניו:

"2+2=4" =~ /2+2/; # לא תואם, + הוא תו מטא
"2+2=4" =~ /2\+2/; # התאמות, \+ מטופל כמו + רגיל
"המרווח הוא [0,1)." =~ /[0,1)./ # הוא שגיאת תחביר!
"המרווח הוא [0,1)." =~ /\[0,1\)\./ # התאמות
"#!/usr/bin/perl" =~ /#!\/ usr\/ סל\/perl/; # התאמות

בביטוי הרגולרי האחרון, הלוכסון הקדמי '/' גם הוא מנוגד לאחור, כי הוא רגיל
תוחם את הביטוי הרגולרי. עם זאת, זה יכול להוביל ל-LTS (תסמונת קיסם נשען), וזהו
לעתים קרובות יותר קריא כדי לשנות תוחמים.

"#!/usr/bin/perl" =~ מ!#\!/usr/bin/perl!; # קל יותר לקריאה

תו הנטוי האחורי '\' הוא תו מטא בעצמו וצריך לחתוך לאחור:

'C:\WIN32' =~ /C:\\WIN/; # התאמות

בנוסף למטא-תווים, יש כמה תווי ASCII שאין להם
מקבילי תווים להדפסה והם מיוצגים במקום זאת על ידי לברוח רצפים. מְשׁוּתָף
דוגמאות הן "\t" עבור כרטיסייה, "\n" עבור שורה חדשה, "\r" עבור החזרת כרכרה ו-"\a" עבור
פעמון (או התראה). אם עדיף לחשוב על המחרוזת שלך כרצף של בתים שרירותיים,
רצף הבריחה האוקטלי, למשל, "\033", או רצף הבריחה הקסדצימלי, למשל, "\x1B" עשוי
להיות ייצוג טבעי יותר לבייטים שלך. הנה כמה דוגמאות לבריחות:

"1000\t2000" =~ m(0\t2) # התאמות
"1000\n2000" =~ /0\n20/ # התאמות
"1000\t2000" =~ /\000\t2/ # לא תואם, "0" ולא "\000"
"cat" =~ /\o{143}\x61\x74/ # התאמות ב-ASCII, אבל דרך מוזרה
# לאיית חתול

אם הסתובבת בפרל זמן מה, כל הדיבורים האלה על רצפי בריחה עשויים להיראות מוכרים.
רצפי בריחה דומים משמשים במחרוזות במירכאות כפולות ולמעשה ב-Regexps ב- Perl
מתייחסים לרוב כמחרוזות במירכאות כפולות. המשמעות היא שניתן להשתמש במשתנים ב
גם ביטויים רגועים. בדיוק כמו מחרוזות במירכאות כפולות, הערכים של המשתנים ב-
ביטוי regexp יוחלף לפני שה- regexp יוערך למטרות התאמה. אז אנחנו
has you

$foo = 'בית';
'חתול בית' =~ /$foo/; # התאמות
'cathouse' =~ /cat$foo/; # התאמות
'חתול בית' =~ /${foo}חתול/; # התאמות

בינתיים הכל טוב. עם הידע לעיל אתה כבר יכול לבצע חיפושים עם רק
על כל ביטוי רגולי של מחרוזת מילולית שאתה יכול לחלום. הנה א מאוד פשוט חיקוי של
תוכנית grep Unix:

% cat > simple_grep
#!/usr/bin/perl
$regexp = shift;
בעוד (<>) {
הדפס אם /$regexp/;
}
^D

% chmod +x simple_grep

% simple_grep abba /usr/dict/words
חרוב
כרוב
כרוב
שַׁבָּת
לשבת בשבת
מוציא שבת
שבתון
נְדָן
נדים

תוכנית זו קלה להבנה. "#!/usr/bin/perl"היא הדרך הסטנדרטית להפעיל את א
תוכנית perl מהקליפה. "$regexp = shift;" שומר את הארגומנט של שורת הפקודה הראשונה בשם
הביטוי הרגולרי שבו יש להשתמש, מה שמשאיר את שאר הארגומנטים של שורת הפקודה להיות מטופלים כאל
קבצים. "while (<>)" עובר לולאות על כל השורות בכל הקבצים. עבור כל שורה,
"הדפס אם /$regexp/;" מדפיס את השורה אם הביטוי הרגולרי תואם לשורה. בשורה הזו, שניהם
"print" ו-"/$regexp/" משתמשים במשתנה ברירת המחדל $_ באופן מרומז.

עם כל הביטויים הרגולריים שלמעלה, אם הביטוי הרגולרי תואם למקום כלשהו במחרוזת, זה היה
נחשב להתאמה. עם זאת, לפעמים נרצה לפרט איפה במחרוזת את
regexp צריך לנסות להתאים. לשם כך, נשתמש ב- עוגן מטא-תווים "^" ו
"$". העוגן "^" פירושו התאמה בתחילת המחרוזת והעוגן "$" פירושו
התאמה בסוף המחרוזת, או לפני שורה חדשה בסוף המחרוזת. הנה איך
הם משומשים:

"עוזר בית" =~ /שומר/; # התאמות
"עוזר בית" =~ /^שומר/; # לא תואם
"עוזר בית" =~ /שומר$/; # התאמות
"עוזר בית\n" =~ /שומר$/; # התאמות

הביטוי הרגולרי השני אינו תואם כי "^" מגביל את "שומר" להתאים רק ב-
תחילת המיתר, אבל ל"עוזר בית" יש שומר שמתחיל באמצע. השלישי
regexp אכן תואם, מכיוון שה-"$" מגביל את "keeper" להתאים רק בסוף ה-
מחרוזת.

כאשר הן "^" והן "$" משמשות בו-זמנית, הביטוי הרגולרי חייב להתאים לשני ה-
ההתחלה והסוף של המחרוזת, כלומר, הביטוי הרגולרי מתאים לכל המחרוזת. לשקול

"keeper" =~ /^keep$/; # לא תואם
"keeper" =~ /^keeper$/; # התאמות
"" =~ /^$/; # ^$ תואם מחרוזת ריקה

הביטוי הרגולרי הראשון אינו תואם כי המחרוזת מכילה יותר מאשר "שמור". מאז
second regexp הוא בדיוק המחרוזת, היא תואמת. שימוש ב-"^" וגם ב-"$" בביטוי רגולרי
מאלץ את המחרוזת השלמה להתאים, כך שהיא נותנת לך שליטה מלאה על אילו מחרוזות
מתאימים ואיזה לא. נניח שאתה מחפש בחור בשם ברט, במחרוזת
על ידי עצמו:

"dogbert" =~ /bert/; # התאמות, אבל לא מה שאתה רוצה

"dilbert" =~ /^ברט/; # לא תואם, אבל ..
"bertram" =~ /^bert/; # התאמות, אז עדיין לא מספיק טוב

"bertram" =~ /^bert$/; # לא תואם, טוב
"dilbert" =~ /^bert$/; # לא תואם, טוב
"ברט" =~ /^ברט$/; # התאמות, מושלם

כמובן, במקרה של מחרוזת מילולית, אפשר באותה קלות להשתמש במחרוזת
השוואה "$string eq 'bert'" וזה יהיה יעיל יותר. הביטוי הרגולרי "^...$".
באמת הופך שימושי כאשר אנו מוסיפים את הכלים החזקים יותר של ביטוי regexp למטה.

שימוש אופי כיתות
למרות שאפשר כבר לעשות הרבה עם הביטויים המילוליים של המחרוזת למעלה, יש לנו רק
שרטה את פני השטח של טכנולוגיית הביטוי הרגולרי. בסעיפים זה ובסעיפים הבאים
נציג מושגי ביטוי רגועים (וסימוני מטא-תווים קשורים) שיאפשרו
ביטוי רגולרי לייצג לא רק רצף תווים בודד, אלא א כל בכיתה שלהם.

מושג אחד כזה הוא של א אופי בכיתה. מחלקה תווים מאפשרת קבוצה של אפשרי
תווים, ולא רק תו בודד, כדי להתאים בנקודה מסוימת ב-a
ביטוי רגולרי. אתה יכול להגדיר שיעורי דמות מותאמים אישית משלך. אלה מסומנים בסוגריים
"[...]", עם קבוצת התווים שיש אולי להתאים בפנים. הנה כמה
דוגמאות:

/חתול/; # מתאים ל'חתול'
/[bcr]at/; # מתאים ל'עטלף', 'חתול' או 'עכברוש'
/item[0123456789]/; # מתאים ל-'item0' או ... או 'item9'
"abc" =~ /[מונית]/; # מתאים ל-'a'

בהצהרה האחרונה, למרות ש'c' הוא התו הראשון בכיתה, 'a' תואם
מכיוון שמיקום התו הראשון במחרוזת הוא הנקודה המוקדמת ביותר שבה
regexp יכול להתאים.

/[yY][eE][sS]/; # התאם 'כן' בצורה חסרת רגישות לאותיות גדולות
# 'כן', 'כן', 'כן' וכו'.

הביטוי הרגולרי הזה מציג משימה נפוצה: בצע התאמה לא תלוית רישיות. פרל מספק דרך
של הימנעות מכל סוגריים אלה פשוט על ידי הוספת 'i' לסוף המשחק. לאחר מכן
"/[yY][eE][sS]/;" ניתן לכתוב מחדש כ-"/yes/i;". ה-'i' מייצג חוסר רגישות רישיות ו
הוא דוגמה לא מתקן של פעולת ההתאמה. נפגוש מתקנים אחרים מאוחר יותר
במדריך.

ראינו בסעיף למעלה שיש דמויות רגילות, שייצגו
עצמם, ודמויות מיוחדות, שהיו זקוקות לאחור "\" כדי לייצג את עצמן.
הדבר נכון גם במחלקת תווים, אבל קבוצות הדמויות הרגילות והמיוחדות
בתוך מחלקת תווים שונים מאלה שמחוץ למחלקת תווים. המיוחד
התווים עבור מחלקת תווים הם "-]\^$" (ומפריד הדפוס, מה שזה לא יהיה).
"]" הוא מיוחד מכיוון שהוא מציין את הסוף של מחלקת תווים. "$" מיוחד בגלל שהוא
מציין משתנה סקלרי. "\" הוא מיוחד בגלל שהוא משמש ברצפי בריחה, פשוט
כמו למעלה. כך מטפלים בתווים המיוחדים "]$\":

/[\]c]def/; # תואם את ']def' או 'cdef'
$x = 'bcr';
/[$x]at/; # מתאים ל'עטלף', 'חתול' או 'עכברוש'
/[\$x]at/; # מתאים ל-'$at' או 'xat'
/[\\$x]at/; # מתאים ל'\at', 'עטלף', 'חתול' או 'עכברוש'

השניים האחרונים קצת מסובכים. ב-"[\$x]", הנטוי האחורי מגן על סימן הדולר, אז
למחלקת התווים יש שני איברים "$" ו-"x". ב-"[\\$x]", הנטוי האחורי מוגן,
אז $x מטופל כמשתנה ומוחלף במירכאות כפולות.

התו המיוחד '-' פועל כמפעיל טווח בתוך מחלקות תווים, כך שא
ניתן לכתוב קבוצה רציפה של תווים כטווח. עם טווחים, המסורבלים
"[0123456789]" ו-"[abc...xyz]" הופכים ל-"[0-9]" ו-"[az] הדק". חלק מהדוגמאות הן

/item[0-9]/; # מתאים ל-'item0' או ... או 'item9'
/[0-9bx-z]aa/; # מתאים ל-'0aa', ..., '9aa',
# 'baa', 'xaa', 'yaa', או 'zaa'
/[0-9a-fA-F]/; # מתאים לספרה הקסדצימלית
/[0-9a-zA-Z_]/; # מתאים לתו "מילה",
# כמו אלה בשם משתנה Perl

אם '-' הוא התו הראשון או האחרון במחלקת תווים, הוא יטופל כאל רגיל
אופי; "[-ab]", "[ab-]" ​​ו-"[a\-b]" כולם שוות ערך.

התו המיוחד "^" במיקום הראשון של מחלקת תווים מציין את a נשלל
אופי בכיתה, התואם לכל תו מלבד אלה שבסוגריים. שניהם וגם
"[^...]" חייב להתאים לתו, אחרת ההתאמה נכשלת. לאחר מכן

/[^a]at/; # אינו תואם ל-'aat' או 'at', אלא מתאים
# כל השאר 'עטלף', 'חתול', '0at', '%at' וכו'.
/[^0-9]/; # תואם תו לא מספרי
/[a^]at/; # מתאים ל-'aat' או '^at'; כאן '^' הוא רגיל

עכשיו, אפילו "[0-9]" יכול להיות מטרד לכתוב מספר פעמים, אז מתוך אינטרס של חיסכון
הקשות והפיכת ביטויים רגועים לקריאה יותר, לפרל יש מספר קיצורים למשותף
כיתות תווים, כפי שמוצג להלן. מאז ההשקה של Unicode, אלא אם כן ה-"//a"
השינוי בתוקף, מחלקות התווים הללו תואמות יותר מסתם כמה תווים ב
טווח ASCII.

· \d תואם ספרה, לא רק [0-9] אלא גם ספרות מתסריטים לא רומיים

· \s תואם תו רווח לבן, הסט [\ \t\r\n\f] ואחרים

· \w תואם תו מילה (אלפאנומרי או _), לא רק [0-9a-zA-Z_] אלא גם ספרות
ודמויות מתסריטים לא רומיים

· \D הוא \d מבוטל; הוא מייצג כל תו אחר מלבד ספרה, או [^\d]

· \S הוא \s מבוטל; הוא מייצג כל תו שאינו רווח לבן [^\s]

· \W הוא \w מבוטל; הוא מייצג כל תו שאינו מילה [^\w]

· התקופה '.' מתאים לכל תו מלבד "\n" (אלא אם השינוי "//s" בתוקף,
כפי שמוסבר להלן).

· \N, כמו הנקודה, תואם לכל תו מלבד "\n", אך הוא עושה זאת ללא קשר ל
האם השינוי "//s" בתוקף.

המשנה "//a", הזמין החל ב-Perl 5.14, משמש להגבלת ההתאמות של
\d, \s ו-\w רק לאלה שבטווח ASCII. זה שימושי כדי למנוע את התוכנית שלך
חשיפה מיותרת ליוניקוד המלא (ולשיקולי האבטחה הנלווים לו)
כאשר כל מה שאתה רוצה הוא לעבד טקסט דמוי אנגלית. (ניתן להכפיל את ה-"a", "//aa", ל
לספק הגבלות אפילו יותר, ולמנוע התאמה לא-רגישת רישיות של ASCII עם לא-
תווי ASCII; אחרת "סימן קלווין" של Unicode יתאים ללא כל מקרה ל-"k" או "K".)

ניתן להשתמש בקיצורי "\d\s\w\D\S\W" הן בתוך והן מחוץ לסוגריים
שיעורי אופי. הנה כמה בשימוש:

/\d\d:\d\d:\d\d/; # מתאים לפורמט זמן hh:mm:ss
/[\d\s]/; # תואם לכל תו ספרה או רווח לבן
/\w\W\w/; # מתאים למילה char, ואחריה א
# char ללא מילה, ואחריה מילה char
/..rt/; # מתאים לכל שני תווים, ואחריו 'rt'
/סוֹף\./; # התאמות 'סוף'.
/סוֹף[.]/; # אותו דבר, תואם 'סוף'.

מכיוון שתקופה היא דמות מטא, יש לברוח ממנה כדי להתאים אותה לדמות רגילה
פרק זמן. מכיוון, למשל, "\d" ו-"\w" הם קבוצות של תווים, זה לא נכון ל
חשבו על "[^\d\w]" בתור "[\D\W]"; למעשה "[^\d\w]" זהה ל-"[^\w]", שהוא ה-
זהה ל-"[\W]". תחשוב על חוקי דמורגן.

למעשה, קיצורי התקופה ו-"\d\s\w\D\S\W" הם בעצמם סוגים של
מחלקות תווים, כך שאלו המוקפות בסוגריים הן רק סוג אחד של תו
מעמד. כאשר אנו צריכים לעשות הבחנה, אנו מתייחסים אליהם כאל "תו בסוגריים".
שיעורים."

עוגן שימושי בביטויים מחודשים בסיסיים הוא ה מילה עוגן "\b". זה תואם גבול
בין תו מילה לתו שאינו מילה "\w\W" או "\W\w":

$x = "חתול בית מצרף בית וחתול";
$x =~ /cat/; # מתאים לחתול ב'חתול בית'
$x =~ /\bcat/; # מתאים לחתול ב-'catenates'
$x =~ /cat\b/; # מתאים לחתול ב'חתול בית'
$x =~ /\bcat\b/; # מתאים ל'חתול' בסוף המחרוזת

שימו לב בדוגמה האחרונה, סוף המחרוזת נחשב לגבול מילים.

עבור עיבוד שפה טבעית (כך, למשל, אפוסתרופים כלולים במילים),
השתמש במקום "\b{wb}"

"לא" =~ / .+? \b{wb} /x; # מתאים לכל המחרוזת

אתה עשוי לתהות מדוע '.' מתאים להכל מלבד "\n" - למה לא לכל דמות? הסיבה
הוא שלעתים קרובות אחד תואם מול שורות ורוצה להתעלם מהשורה החדשה
דמויות. לדוגמה, בעוד שהמחרוזת "\n" מייצגת שורה אחת, נרצה
תחשוב על זה כריק. לאחר מכן

"" =~ /^$/; # התאמות
"\n" =~ /^$/; # התאמות, עוגנים $ לפני "\n"

"" =~ /./; # לא תואם; זה צריך char
"" =~ /^.$/; # לא תואם; זה צריך char
"\n" =~ /^.$/; # לא תואם; הוא צריך char מלבד "\n"
"a" =~ /^.$/; # התאמות
"a\n" =~ /^.$/; # התאמות, עוגנים $ לפני "\n"

התנהגות זו נוחה, מכיוון שבדרך כלל אנו רוצים להתעלם משורות חדשות כאשר אנו סופרים ו
להתאים תווים בשורה. עם זאת, לפעמים אנחנו רוצים לעקוב אחר שורות חדשות. אָנוּ
אולי אפילו רוצה ש-"^" ו-"$" יעגונו בתחילת ובסוף של שורות בתוך המחרוזת,
במקום רק ההתחלה והסוף של המחרוזת. פרל מאפשרת לנו לבחור בין
התעלמות ותשומת לב לשורות חדשות על ידי שימוש במתני "//s" ו-"//m". "//s"
ו-"//m" מייצגים שורה אחת ורב-קו והם קובעים אם מחרוזת אמורה
להתייחס כמחרוזת אחת רציפה, או כמערכת של קווים. שני המשתנים משפיעים על שניים
היבטים של האופן שבו הביטוי הרגולרי מתפרש: 1) כיצד ה-'.' מחלקת תווים מוגדרת, ו
2) שבו העוגנים "^" ו-"$" מסוגלים להתאים. להלן ארבעת האפשרויות
שילובים:

· ללא שינויים (//): התנהגות ברירת מחדל. '.' מתאים לכל תו מלבד "\n". "^"
מתאים רק בתחילת המחרוזת ו-"$" מתאים רק בסוף או לפני
שורה חדשה בסוף.

· s משנה (//s): התייחס למחרוזת כשורה אחת ארוכה. '.' מתאים לכל דמות, אפילו
"\n". "^" מתאים רק בתחילת המחרוזת ו-"$" מתאים רק בסוף
או לפני שורה חדשה בסוף.

· m modifier (//m): התייחס למחרוזת כאל קבוצה של שורות מרובות. '.' מתאים לכל דמות
מלבד "\n". "^" ו-"$" יכולים להתאים בהתחלה או בסוף כל קו בתוך
מחרוזת.

· גם s ו-m משנה (//sm): התייחס למחרוזת כאל שורה אחת ארוכה, אך גלה מספר רב של
שורות. '.' מתאים לכל תו, אפילו "\n". "^" ו-"$", לעומת זאת, מסוגלים להתאים
בהתחלה או בסוף כל קו בתוך המחרוזת.

הנה דוגמאות של "//s" ו-"//m" בפעולה:

$x = "היתה פעם ילדה\nשתכנתה בפרל\n";

$x =~ /^מי/; # לא תואם, "מי" לא בתחילת המחרוזת
$x =~ /^מי/ים; # לא תואם, "מי" לא בתחילת המחרוזת
$x =~ /^מי/מ; # התאמות, "מי" בתחילת השורה השנייה
$x =~ /^מי/sm; # התאמות, "מי" בתחילת השורה השנייה

$x =~ /girl.Who/; # לא תואם, "." לא תואם "\n"
$x =~ /girl.Who/s; # התאמות, "." תואם "\n"
$x =~ /girl.Who/m; # לא תואם, "." לא תואם "\n"
$x =~ /girl.Who/sm; # התאמות, "." תואם "\n"

לרוב, התנהגות ברירת המחדל היא מה שרוצים, אבל "//s" ו-"//m" כן
מדי פעם שימושי מאוד. אם נעשה שימוש ב-"//m", ההתחלה של המחרוזת עדיין יכולה להיות
תואם עם "\A" ועדיין ניתן להתאים את קצה המחרוזת עם העוגנים "\Z"
(תואם הן את הסוף והן את השורה החדשה לפני, כמו "$"), ואת "\z" (תואם רק את הסוף):

$x =~ /^מי/מ; # התאמות, "מי" בתחילת השורה השנייה
$x =~ /\AWho/m; # לא תואם, "מי" אינו בתחילת המחרוזת

$x =~ /girl$/m; # התאמות, "ילדה" בסוף השורה הראשונה
$x =~ /girl\Z/m; # לא תואם, "ילדה" לא נמצא בסוף המחרוזת

$x =~ /Perl\Z/m; # התאמות, "Perl" נמצא בשורה חדשה לפני סיום
$x =~ /Perl\z/m; # לא תואם, "Perl" לא נמצא בסוף המחרוזת

כעת אנו יודעים כיצד ליצור אפשרויות בחירה בין מחלקות דמויות ב-Regexp. מה לגבי
אפשרויות בחירה בין מילים או מחרוזות תווים? בחירות כאלה מתוארות בסעיף הבא.

תואם זֶה or זֶה
לפעמים היינו רוצים שהביטוי הרגולרי שלנו יוכל להתאים מילים אפשריות שונות או
מחרוזות תווים. זה מושג על ידי שימוש ב- הִתחַלְפוּת תו מטא "|". ל
להתאים "כלב" או "חתול", אנו יוצרים את הביטוי הרגולרי "כלב|חתול". כמו קודם, פרל תנסה להתאים את
regexp בנקודה המוקדמת ביותר האפשרית במחרוזת. בכל עמדת דמות, פרל
תחילה ינסה להתאים את החלופה הראשונה, "כלב". אם "כלב" לא מתאים, פרל כן
ואז נסה את החלופה הבאה, "חתול". אם גם "חתול" לא תואם, אז ההתאמה נכשלת
ופרל עובר למיקום הבא במחרוזת. כמה דוגמאות:

"חתולים וכלבים" =~ /חתול|כלב|ציפור/; # מתאים ל"חתול"
"חתולים וכלבים" =~ /כלב|חתול|ציפור/; # מתאים ל"חתול"

למרות ש"כלב" הוא החלופה הראשונה בביטוי הרגולרי השני, "חתול" מסוגל להתאים
מוקדם יותר במחרוזת.

"חתולים" =~ /c|ca|cat|cats/; # תואם ל-"c"
"חתולים" =~ /חתולים|חתול|ca|c/; # מתאים ל"חתולים"

כאן, כל החלופות מתאימות במיקום המיתר הראשון, כך שהחלופה הראשונה היא
זו שתואמת. אם חלק מהחלופות הן חיתוך של האחרות, שים את
הארוכים ביותר קודם כדי לתת להם הזדמנות להתאים.

"cab" =~ /a|b|c/ # מתאים ל-"c"
# /a|b|c/ == /[abc]/

הדוגמה האחרונה מציינת שמחלקות תווים הן כמו חילופי תווים.
במיקום דמות נתון, האלטרנטיבה הראשונה המאפשרת להתאים את הביטוי הרגולרי ל
להצליח תהיה זו שתתאים.

הַקבָּצָה דברים ו היררכי תואם
החלפה מאפשרת לביטוי מחודש לבחור בין חלופות, אבל כשלעצמה היא כזו
לא מספק. הסיבה היא שכל חלופה היא ביטוי מחודש שלם, אבל מתישהו אנחנו רוצים
חלופות רק לחלק מהביטוי הרגולרי. לדוגמה, נניח שאנו רוצים לחפש
חתולי בית או עוזרות בית. הביטוי הרגולרי "חתול בית| עוזר בית" מתאים לחשבון, אבל כן
לא יעיל כי היינו צריכים להקליד "בית" פעמיים. זה יהיה נחמד לקבל חלקים של
regexp יהיה קבוע, כמו "בית", ולחלקים מסוימים יש חלופות, כמו "חתול|שומר".

השמיים הַקבָּצָה מטא-תווים "()" פותרים את הבעיה הזו. קיבוץ מאפשר לחלקים של ביטוי מחודש
להתייחס כיחידה אחת. חלקים של ביטוי רגולרי מקובצים על ידי סגירתם
סוגריים. כך נוכל לפתור את "חתול הבית| עוזרת בית" על ידי יצירת הביטוי הרגולרי כ
"בית(חתול|שומר)". הביטוי הרגולרי "בית(חתול|שומר)" פירושו התאמת "בית" ואחריו
או "חתול" או "שומר". יש עוד כמה דוגמאות

/(א|ב)ב/; # מתאים ל-'ab' או 'bb'
/(ac|b)b/; # תואם את 'acb' או 'bb'
/(^a|b)c/; # תואם את 'ac' בתחילת המחרוזת או 'bc' בכל מקום
/(a|[bc])d/; # מתאים ל-'ad', 'bd' או 'cd'

/house(cat|)/; # מתאים ל'חתול בית' או 'בית'
/house(cat(s|)|)/; # מתאים ל'חתול בית' או 'חתול בית' או
# 'בית'. ניתן לקנן קבוצות הערות.

/(19|20|)\d\d/; # שנים התאמה 19xx, 20xx, או בעיית Y2K, xx
"20" =~ /(19|20|)\d\d/; # תואם לחלופה null '()\d\d',
# כי '20\d\d' לא יכול להתאים

החלפות מתנהגות באותה צורה בקבוצות כמו מחוץ להן: במיקום מיתר נתון, ה
נלקחת החלופה השמאלית ביותר המאפשרת לביטוי הרגולרי להתאים. אז בדוגמה האחרונה ב
מיקום המיתר הראשון, "20" תואם את החלופה השנייה, אבל לא נשאר כלום
מעל כדי להתאים לשתי הספרות הבאות "\d\d". אז פרל עוברת לחלופה הבאה, אשר
היא החלופה האפסית וזה עובד, שכן "20" הוא שתי ספרות.

התהליך של נסיון אלטרנטיבה אחת, לראות אם היא תואמת, ולהמשיך הלאה
אלטרנטיבה, תוך כדי חזרה למחרוזת מהמקום שבו נוסתה החלופה הקודמת,
אם לא, נקרא מסלול חזרה. המונח 'חזרה לאחור' בא מהרעיון ש
התאמת ביטוי מחודש הוא כמו טיול ביער. התאמה מוצלחת של ביטוי רגולרי הוא כמו
הגעה ליעד. יש הרבה ראשי שבילים אפשריים, אחד לכל מיתר
עמדה, וכל אחד מהם נבדק לפי הסדר, משמאל לימין. מכל ראש שביל עשוי להיות
שבילים רבים, חלקם מביאים אותך לשם, וחלקם מבוי סתום. כשאתה הולך
לאורך שביל ולצאת למבוי סתום, אתה צריך לחזור לאורך השביל למסלול מוקדם יותר
הצבע כדי לנסות מסלול אחר. אם תגיע ליעד שלך, אתה עוצר מיד ושוכח
על לנסות את כל השבילים האחרים. אתה מתמיד, ורק אם ניסית את כל
שבילים מכל ראשי השבילים ולא הגיעו ליעדך, אתה מצהיר
כישלון. כדי להיות קונקרטי, הנה ניתוח שלב אחר שלב של מה פרל עושה כשהיא מנסה
כדי להתאים לביטוי הרגולרי

"abcde" =~ /(abd|abc)(df|d|de)/;

0 התחל עם האות הראשונה במחרוזת 'a'.

1 נסה את החלופה הראשונה בקבוצה הראשונה 'abd'.

2 התאם את 'a' ואחריו 'ב'. בינתיים הכל טוב.

3 'd' בביטוי הרגולרי לא תואם 'c' במחרוזת - מבוי סתום. אז חזור שניים
תווים ובחר את החלופה השנייה בקבוצה הראשונה 'abc'.

4 התאם את 'a' ואחריו 'b' ואחריו 'c'. אנחנו בפיתוח וסיפקנו את
קבוצה ראשונה. הגדר $1 ל-'abc'.

5 עברו לקבוצה השנייה ובחרו בחלופה הראשונה 'df'.

6 התאימו ל-'d'.

7 'f' בביטוי הרגולרי לא תואם 'e' במחרוזת, אז מבוי סתום. חזרה אחת
תו ובחר את החלופה השנייה בקבוצה השנייה 'd'.

8 התאמות 'ד'. הקיבוץ השני מרוצה, אז הגדר $2 ל-'d'.

9 אנחנו בסוף הביטוי הרגולרי, אז סיימנו! התאמנו את 'abcd' מתוך
מחרוזת "abcde".

יש כמה דברים לשים לב לניתוח זה. ראשית, החלופה השלישית ב
גם הקבוצה השנייה 'דה' מאפשרת התאמה, אבל עצרנו לפני שהגענו אליה - בשלב נתון
מיקום הדמות, הכי שמאל מנצח. שנית, הצלחנו להשיג התאמה בהתחלה
מיקום התו של המחרוזת 'a'. אם לא היו התאמות בעמדה הראשונה,
פרל יעבור למיקום הדמות השני 'b' וינסה את ההתאמה מחדש.
רק כאשר כל הנתיבים האפשריים בכל עמדות הדמות האפשריות מוצו
פרל מוותר ומצהיר "$string =~ /(abd|abc)(df|d|de)/;" להיות שקר.

אפילו עם כל העבודה הזו, התאמת ביטויים רגועים מתרחשת מהר להפליא. כדי להאיץ את העניינים,
Perl מרכיב את ה-regexp לרצף קומפקטי של קודים שיכולים להתאים לרוב בתוך a
מטמון מעבד. כאשר הקוד מבוצע, קודים אלה יכולים לפעול במלוא המצערת
ולחפש מהר מאוד.

מחלץ גפרורים
המטא-תווים המקבצים "()" ממלאים גם תפקיד אחר לגמרי: הם
לאפשר חילוץ של חלקי מיתר שתואמים. זה מאוד שימושי למצוא
לברר מה מתאים ולעיבוד טקסט באופן כללי. עבור כל קיבוץ, החלק ש
התאמה בפנים נכנסת למשתנים המיוחדים $1, $2 וכו'. ניתן להשתמש בהם בדיוק כמו
משתנים רגילים:

# חלץ שעות, דקות, שניות
if ($time =~ /(\d\d):(\d\d):(\d\d)/) { # match hh:mm:ss format
$hours = $1;
$דקות = $2;
$seconds = $3;
}

כעת, אנו יודעים שבהקשר סקלרי, "$time =~ /(\d\d):(\d\d):(\d\d)/" מחזיר אמת או
ערך שקרי. עם זאת, בהקשר של רשימה, הוא מחזיר את רשימת הערכים התואמים
"($1,$2,$3)". אז נוכל לכתוב את הקוד בצורה קומפקטית יותר

# חלץ שעות, דקות, שניות
($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);

אם הקבוצות ב-Regexp מקוננות, $1 מקבל את הקבוצה עם הפתיחה השמאלית ביותר
סוגריים, 2$ סוגרי הפתיחה הבא וכו'. הנה ביטוי מחודש עם קבוצות מקוננות:

/(ab(cd|ef)((gi)|j))/;
1

אם הביטוי הרגולרי הזה תואם, $1 מכיל מחרוזת שמתחילה ב-'ab', $2 מוגדר כ-'cd'
או 'ef', $3 שווה ל-'gi' או 'j', ו-$4 מוגדר ל-'gi', בדיוק כמו $3, או שהוא
נשאר בלתי מוגדר.

מטעמי נוחות, Perl מגדיר $+ למחרוזת המוחזקת על ידי המספר הגבוה ביותר של $1, $2,...
הוקצה (ובקצת קשור, $^N לערך של $1, $2,... לאחרונה
שהוקצה; כלומר $1, $2,... המשויך לסוגרי הסגירה הימני ביותר בשימוש ב
המשחק).

הפניות לאחור
קשורים קשר הדוק למשתנים התואמים $1, $2, ... הם הפניות אחוריות "\g1",
"\g2",... הפניות לאחור הן פשוט משתנים תואמים שניתן להשתמש בהם בתוך ביטוי מחודש.
זו תכונה ממש נחמדה; מה שמתאים מאוחר יותר ב-Regexp עשוי להיות תלוי במה
תואם מוקדם יותר בביטוי הרגולרי. נניח שרצינו לחפש מילים כפולות בטקסט,
כמו 'ה'. הביטוי הרגולרי הבא מוצא את כל הכפילים של 3 אותיות עם רווח ביניהם:

/\b(\w\w\w)\s\g1\b/;

הקיבוץ מקצה ערך ל-\g1, כך שאותו רצף בן 3 אותיות משמש לשניהם
חלקים.

משימה דומה היא למצוא מילים המורכבות משני חלקים זהים:

% simple_grep '^(\w\w\w\w|\w\w\w|\w\w|\w)\g1$' /usr/dict/words
בריברי
קקי
קוקו
אמא
רִשׁרוּשׁ
אבא

לביטוי הרגולרי יש קיבוץ יחיד שמתחשב בשילובים של 4 אותיות, ולאחר מכן 3 אותיות
שילובים וכו', ומשתמש ב-"\g1" כדי לחפש חזרה. למרות ש-$1 ו-"\g1" מייצגים
אותו דבר, יש להקפיד על שימוש במשתנים תואמים $1, $2,... בלבד בחוץ a
ביטוי regexp והפניות לאחור "\g1", "\g2",... בלבד בתוך ביטוי מחודש; לא לעשות זאת עלול להוביל
תוצאות מפתיעות ולא מספקות.

קרוב משפחה הפניות אחוריות
ספירת הסוגריים הפותחים כדי לקבל את המספר הנכון עבור הפניה לאחור היא שגיאה-
מועדים ברגע שיש יותר מקבוצת לכידה אחת. טכניקה נוחה יותר
הפך זמין עם Perl 5.10: הפניות אחוריות יחסיות. להתייחס לאלתר
קבוצת הלכידה הקודמת יכולה לכתוב כעת "\g{-1}", הבאה אך האחרונה זמינה דרך
"\g{-2}", וכן הלאה.

עוד סיבה טובה בנוסף לקריאות ולתחזוקה לשימוש ב-relative
הפניות לאחור מומחשות על ידי הדוגמה הבאה, שבה דפוס פשוט עבור
נעשה שימוש במיתרים מוזרים תואמים:

$a99a = '([az])(\d)\g2\g1'; # מתאים ל-a11a, g22g, x33x וכו'.

כעת, לאחר שהתבנית הזו מאוחסנת כמחרוזת שימושית, אנו עשויים להתפתות להשתמש בה בתור
חלק מתבנית אחרת:

$line = "code=e99e";
if ($line =~ /^(\w+)=$a99a$/){ # התנהגות בלתי צפויה!
הדפס "$1 חוקי\n";
אחר} {
הדפס "שורה רעה: '$line'\n";
}

אבל זה לא תואם, לפחות לא כמו שאפשר לצפות. רק לאחר הכנסת ה
אינטרפולציה $a99a ובהסתכלות על הטקסט המלא שנוצר של הביטוי הרגולרי ברור ש
ההפניות לאחור חזרו. תת הביטוי "(\w+)" חטף את מספר 1 ו
הורידו את הקבוצות ב-$a99a בדרגה אחת. ניתן להימנע מכך על ידי שימוש ביחסי
הפניות לאחור:

$a99a = '([az])(\d)\g{-1}\g{-2}'; # בטוח לביצוע אינטרפולציה

שם הפניות אחוריות
Perl 5.10 הציג גם קבוצות לכידה עם שם והפניות לאחור עם שם. לצרף שם
לקבוצת לכידה, אתה כותב או "(? ...)" או "(?'שם'...)". ה
הפניה לאחור עשויה להיכתב כ"\g{שם}". מותר לצרף אותו הדבר
שם ליותר מקבוצה אחת, אבל אז רק השמאלית ביותר מהקבוצה בעלת השם יכול להיות
הפניה. מחוץ לתבנית נגישה לקבוצת לכידה עם שם דרך ה-"%+"
hash.

בהנחה שעלינו להתאים תאריכים בלוח שנה שעשויים להינתן באחד מהשלושה
פורמטים yyyy-mm-dd, mm/dd/yyyy או dd.mm.yyyy, נוכל לכתוב שלוש תבניות מתאימות בהן
אנו משתמשים ב-'d', 'm' ו-'y' בהתאמה בתור שמות הקבוצות הלוכדות את
מרכיבים של תאריך. פעולת ההתאמה משלבת את שלושת הדפוסים כחלופות:

$fmt1 = '(? \d\d\d\d)-(? \d\d)-(? \d\d)';
$fmt2 = '(? \d\d)/(? \d\d)/(? \d\d\d\d)';
$fmt3 = '(? \d\d)\.(? \d\d)\.(? \d\d\d\d)';
עבור $d qw שלי (2006-10-21 15.01.2007 10/31/2005){
if ($d =~ m{$fmt1|$fmt2|$fmt3}){
הדפס "day=$+{d} month=$+{m} year=$+{y}\n";
}
}

אם אחת מהחלופות תואמת, ה-hash "%+" חייב להכיל את שלושת ערכי המפתח
זוגות.

חלופה ללכוד קבוצה סִפְרוּר
טכניקת מספור קבוצות לכידה נוספת (גם מ- Perl 5.10) עוסקת ב-
בעיה של התייחסות לקבוצות בתוך סט של חלופות. שקול דפוס עבור
התאמה לשעה ביום, בסגנון אזרחי או צבאי:

if ( $time =~ /(\d\d|\d):(\d\d)|(\d\d)(\d\d)/ ){
# שעה ודקה תהליך
}

עיבוד התוצאות דורש הצהרת if נוספת כדי לקבוע אם $1 ו-$2
או $3 ו-$4 מכילים את הטובים. יהיה קל יותר אם נוכל להשתמש במספרי הקבוצה 1 ו-2
גם בחלופה השנייה, וזה בדיוק מה שהמבנה בסוגריים
"(?|...)", להגדיר סביב אלטרנטיבה משיג. הנה גרסה מורחבת של הקודמת
תַבְנִית:

if($time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))\s+([AZ][AZ][ AZ])/){
הדפס "שעה=$1 דקה=$2 אזור=$3\n";
}

בתוך קבוצת המספור החלופית, מספרי קבוצות מתחילים באותו מיקום עבור כל אחד מהם
חֲלוּפָה. לאחר הקבוצה, המספור ממשיך כשאחד גבוה מהמקסימום אליו הגיע
על פני כל האלטרנטיבות.

עמדה מידע
בנוסף למה שהותאם, פרל מספקת גם את העמדות של מה שהותאם
התוכן של המערכים "@-" ו-"@+". "$-[0]" הוא המיקום של ההתחלה של השלם
match ו-$+[0] הוא המיקום של הסיום. באופן דומה, "$-[n]" הוא המיקום של ה-
תחילת ההתאמה של $n ו-$+[n] הוא המיקום של הסוף. אם $n אינו מוגדר, אז כן
"$-[n]" ו-$+[n]. ואז הקוד הזה

$x = "מממ...סופגנייה, חשב הומר";
$x =~ /^(Mmm|Yech)\.\.\.(סופגנייה|אפונה)/; # התאמות
foreach $exp (1..$#-) {
הדפס "תאם $exp: '${$exp}' במיקום ($-[$exp],$+[$exp])\n";
}

הדפסים

התאמה 1: 'מממ' בעמדה (0,3)
התאמה 2: 'סופגנייה' בעמדה (6,11)

גם אם אין קבוצות ב-Regexp, עדיין אפשר לברר מה בדיוק
תואם במחרוזת. אם אתה משתמש בהם, Perl תגדיר "$`" לחלק של המחרוזת שלפניו
ההתאמה, תגדיר $& לחלק של המחרוזת שתאם, ותגדיר "$'" ל-
חלק מהמחרוזת לאחר המשחק. דוגמה:

$x = "החתול תפס את העכבר";
$x =~ /cat/; # $` = 'ה', $& = 'חתול', $' = ' תפס את העכבר'
$x =~ /the/; # $` = '', $& = 'ה', $' = 'חתול תפס את העכבר'

בהתאמה השנייה, "$`" שווה ל-'' כי הביטוי הרגולרי התאים לתו הראשון
מיקום במיתר ונעצר; הוא מעולם לא ראה את ה'ה' השני.

אם הקוד שלך אמור לרוץ על גרסאות Perl מוקדמות יותר מ-5.20, כדאי לציין
השימוש ב-"$`" ו-"$'" מאט את התאמת הביטוי הרגולרי לא מעט, בעוד ש-$& מאט אותו ל-
במידה פחותה, כי אם הם משמשים ב-Regexp אחד בתוכנית, הם נוצרים עבור
את כל ביטויים מחודשים בתוכנית. אז אם ביצועים גולמיים הם המטרה של היישום שלך, הם
יש להימנע. אם אתה צריך לחלץ את מחרוזות המשנה המתאימות, השתמש ב-"@-" ו-"@+"
במקום זאת:

$` זהה ל-substr( $x, 0, $-[0] )
$& זהה ל-substr( $x, $-[0], $+[0]-$-[0] )
$' זהה ל-substr( $x, $+[0] )

החל מ-Perl 5.10, המשתנים "${^PREMATCH}", "${^MATCH}" ו-"${^POSTMATCH}" עשויים להיות
בשימוש. אלה מוגדרים רק אם השינוי "/p" קיים. כתוצאה מכך הם לא
להעניש את שאר התוכנית. ב-Perl 5.20, "${^PREMATCH}", "${^MATCH}" ו
"${^POSTMATCH}" זמינים בין אם נעשה שימוש ב-"/p" או לא (השינוי הוא
התעלמו), ו-"$`", "$'" ו-$& אינם גורמים להפרש מהירות כלשהו.

אי לכידה קבוצות
קבוצה שנדרשת לאגד קבוצה של חלופות עשויה להיות שימושית או לא
קבוצת לכידה. אם לא, זה פשוט יוצר תוספת מיותרת לסט של
ערכי קבוצת לכידה זמינים, בתוך ומחוץ לביטוי הרגולרי. אי לכידה
קבוצות, המסומנות ב-"(?:regexp)", עדיין מאפשרות להתייחס ל-Regexp כיחידה אחת,
אבל אל תקים קבוצת לכידה בו-זמנית. גם לכידה וגם לא לכידה
קבוצות מורשות להתקיים במקביל באותו ביטוי רגולרי. כי אין מיצוי,
קבוצות ללא לכידה מהירות יותר מקבוצות לכידה. קבוצות שאינן לוכדות הן
שימושי גם לבחירה בדיוק אילו חלקים של ביטוי רגולרי יש לחלץ להתאמה
משתנים:

# להתאים למספר, $1-$4 מוגדרים, אבל אנחנו רוצים רק $1
/([+-]?\ *(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)/;

# התאם מספר מהר יותר , רק $1 מוגדר
/([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)/;

# התאם מספר, קבל $1 = מספר שלם, $2 = מעריך
/([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE]([+-]?\d+))?)/;

קבוצות שאינן לוכדות שימושיות גם להסרת אלמנטים מטרידים שנאספו מא
פעולת פיצול כאשר סוגריים נדרשים מסיבה כלשהי:

$x = '12aba34ba5';
@num = split /(a|b)+/, $x; # @num = ('12','a','34','a','5')
@num = split /(?:a|b)+/, $x; # @num = ('12','34','5')

ב-Perl 5.22 ואילך, ניתן להגדיר את כל הקבוצות ב-Regexp ללא לכידה על ידי שימוש
הדגל החדש "/n":

"שלום" =~ /(היי|שלום)/n; # $1 לא מוגדר!

ראה "n" ב-perlre למידע נוסף.

תואם חזרות
הדוגמאות בסעיף הקודם מציגות חולשה מעצבנת. רק התאמנו
מילים של 3 אותיות, או חתיכות של מילים של 4 אותיות או פחות. היינו רוצים להיות מסוגלים להתאים
מילים או, באופן כללי יותר, מחרוזות בכל אורך, מבלי לכתוב חלופות מייגעות
כמו "\w\w\w\w|\w\w\w|\w\w|\w".

זו בדיוק הבעיה מכמת מטא-תווים "?", "*", "+" ו-"{}" היו
נוצר עבור. הם מאפשרים לנו להגדיר את מספר החזרות עבור חלק מ-reexp we
רואים כהתאמה. מכמתים שמים מיד אחרי הדמות, הדמות
מחלקה, או קבוצה שאנו רוצים לציין. יש להם את המשמעויות הבאות:

· "א?" פירושו: התאמת 'a' 1 או 0 פעמים

· "a*" פירושו: התאמת 'a' 0 פעמים או יותר, כלומר כל מספר פעמים

· "a+" פירושו: התאמת 'a' פעם אחת או יותר, כלומר לפחות פעם אחת

· "a{n,m}" פירושו: להתאים לפחות "n" פעמים, אך לא יותר מ-"m" פעמים.

· "a{n,}" פירושו: להתאים לפחות "n" או יותר פעמים

· "a{n}" פירושו: להתאים בדיוק "n" פעמים

הנה כמה דוגמאות:

/[az]+\s+\d*/; # התאם מילה קטנה, רווח אחד לפחות, ו
# כל מספר של ספרות
/(\w+)\s+\g1/; # התאם מילים כפולות באורך שרירותי
/כן אני; # תואם ל-'y', 'Y', או 'yes' שאינו תלוי רישיות
$year =~ /^\d{2,4}$/; # ודא שהשנה היא לפחות 2 אך לא יותר
# מ-4 ספרות
$year =~ /^\d{4}$|^\d{2}$/; # התאמה טובה יותר; לזרוק תאריכים בני 3 ספרות
$year =~ /^\d{2}(\d{2})?$/; # אותו דבר כתוב אחרת.
# עם זאת, זה לוכד את שני האחרונים
# ספרות ב-$1 והשנייה לא.

% simple_grep '^(\w+)\g1$' /usr/dict/words # זה לא קל יותר?
בריברי
קקי
קוקו
אמא
רִשׁרוּשׁ
אבא

עבור כל המכמתים הללו, פרל תנסה להתאים כמה שיותר מהמחרוזת,
תוך מתן אפשרות לביטוי הרגולרי להצליח. לכן עם "/a?.../", פרל תנסה קודם כל
התאם את הביטוי הרגולרי עם הווה "a"; אם זה לא יצליח, Perl תנסה להתאים את הביטוי הרגולרי
ללא הווה "א". עבור המכמת "*", נקבל את הדברים הבאים:

$x = "החתול בכובע";
$x =~ /^(.*)(cat)(.*)$/; # התאמות,
# $1 = 'ה'
# $2 = 'חתול'
# $3 = 'בכובע'

וזה מה שאנחנו עשויים לצפות, הגפרור מוצא את ה"חתול" היחיד בחוט וננעל עליו
זה. עם זאת, שקול את הביטוי הרגולרי הזה:

$x =~ /^(.*)(at)(.*)$/; # התאמות,
# $1 = 'החתול ב-h'
# $2 = 'ב'
# $3 = '' (0 תווים תואמים)

אפשר לנחש בתחילה שפרל ימצא את ה"ב" ב"חתול" ויעצור שם, אבל זה
לא ייתן את המחרוזת הארוכה ביותר האפשרית לכמת הראשון ".*". במקום זאת, ה
הכמת הראשון ".*" תופס כמה שיותר מהמחרוזת בעוד שעדיין יש את
התאמה לביטוי רגיל. בדוגמה זו, זה אומר שיש את הרצף "at" עם ה-"at" האחרון בפנים
המיתר. העיקרון החשוב הנוסף המודגם כאן הוא שכאשר יש שניים או
אלמנטים נוספים בביטוי רגולרי, ה השמאלי ביותר מכמת, אם יש כזה, יצליח לתפוס אותו הרבה
של המיתר ככל האפשר, ומשאיר את שאר הביטוי הרגולרי להילחם על שאריות. כך פנימה
הדוגמה שלנו, הכמת הראשון ".*" תופס את רוב המחרוזת, בעוד שהשני
מכמת ".*" מקבל את המחרוזת הריקה. מכמתים שתופסים כמה שיותר מהמחרוזת
אפשרי נקראים מרבי להתאים or חמדן מכמתים.

כאשר ביטוי רגולרי יכול להתאים למחרוזת בכמה דרכים שונות, אנו יכולים להשתמש בעקרונות
למעלה כדי לחזות באיזו דרך הביטוי הרגולרי יתאים:

· עיקרון 0: בהתחשב במכלול, כל ביטוי רגולרי יתואם בהקדם האפשרי
מיקום במחרוזת.

· עקרון 1: בחילופין "א|ב|ג...", החלופה השמאלית ביותר המאפשרת א
התאמה עבור כל הביטוי הרגולרי יהיה זה שבו נעשה שימוש.

· עקרון 2: מכמת ההתאמה המקסימלית "?", "*", "+" ו-"{n,m}" יהיו ב
התאמה כללית לכמה שיותר מהמחרוזת ועדיין לאפשר את כל הביטוי הרגולרי
להתאים.

· עקרון 3: אם יש שני אלמנטים או יותר בביטוי רגולרי, החמדן השמאלי ביותר
quantifier, אם בכלל, יתאים לכמה שיותר מהמחרוזת ועדיין מאפשר
כל הביטוי הרגולרי כדי להתאים. המכמת החמדן הבא השמאלי ביותר, אם בכלל, ינסה לעשות זאת
התאם כמה שיותר מהמחרוזת שנשארה זמינה עבורו, בעודו עדיין
מה שמאפשר לכל הביטוי הרגולרי להתאים. וכן הלאה, עד שכל רכיבי הביטוי הרגולרי יהיו
שבע רצון.

כפי שראינו לעיל, עקרון 0 גובר על האחרים. הביטוי הרגולרי יהיה מותאם כ
מוקדם ככל האפשר, כשהעקרונות האחרים קובעים כיצד הביטוי הרגולרי מתאים לזה
עמדת הדמות המוקדמת ביותר.

הנה דוגמה לעקרונות אלה בפעולה:

$x = "רפובליקת התכנות של פרל";
$x =~ /^(.+)(e|r)(.*)$/; # התאמות,
# $1 = 'רפובליקת התכנות של Pe'
# $2 = 'r'
# $3 = 'l'

הביטוי הרגולרי הזה תואם במיקום המחרוזת המוקדם ביותר, 'T'. אפשר לחשוב ש"ה", הוויה
השמאלי ביותר בסירוגין, יהיה מותאם, אבל "r" מייצר את המיתר הארוך ביותר ב-
מכמת ראשון.

$x =~ /(m{1,2})(.*)$/; # התאמות,
# $1 = 'ממ'
# $2 = 'הרפובליקה של פרל'

כאן, ההתאמה המוקדמת ביותר האפשרית היא ב-'m' הראשון ב"תכנות". "m{1,2}" הוא ה-
מכמת ראשון, כך שהוא יתאים ל-"מ"מ מקסימלי.

$x =~ /.*(מ{1,2})(.*)$/; # התאמות,
# $1 = 'm'
# $2 = 'הרפובליקה של פרל'

כאן, הביטוי הרגולרי מתאים בתחילת המחרוזת. הכמת הראשון ".*" תופס כ
ככל האפשר, תוך השארת 'm' בודד עבור המכמת השני "m{1,2}".

$x =~ /(.?)(מ{1,2})(.*)$/; # התאמות,
# $1 = 'a'
# $2 = 'ממ'
# $3 = 'הרפובליקה של פרל'

כאן, ".?" אוכל את התו המקסימלי שלו במיקום המוקדם ביותר האפשרי במחרוזת,
'a' ב"תכנות", ומשאיר ל-"m{1,2}" את ההזדמנות להתאים את שני ה-m. סוף כל סוף,

"aXXXb" =~ /(X*)/; # התאמות עם $1 = ''

מכיוון שהוא יכול להתאים לאפס עותקים של 'X' בתחילת המחרוזת. אם אתה בהחלט
רוצה להתאים לפחות 'X' אחד, השתמש ב-"X+", לא "X*".

לפעמים חמדנות זה לא טוב. לפעמים, נרצה שמכמתים יתאימו ל-a מינימלי לְחַבֵּר
של מיתר, ולא של יצירה מקסימלית. למטרה זו, לארי וול יצר את מינימלי
להתאים or לא חמדן מכמים "??", "*?", "+?" ו-"{}?". אלו הם הרגילים
מכמתים עם "?" צורף אליהם. יש להם את המשמעויות הבאות:

· "א??" פירושו: התאם 'a' 0 או 1 פעמים. נסה קודם 0, ואז 1.

· "א*?" פירושו: להתאים את 'a' 0 פעמים או יותר, כלומר, כל מספר פעמים, אך כמה פעמים
אפשרי

· "a+?" פירושו: להתאים את 'a' פעם אחת או יותר, כלומר לפחות פעם אחת, אך כמה פעמים
אפשרי

· "א{נ,מ}?" פירושו: להתאים לפחות "n" פעמים, לא יותר מ-"m" פעמים, כמה פעמים
אפשרי

· "א{נ,}?" פירושו: להתאים לפחות "n" פעמים, אך כמה שפחות פעמים

· "א{n}?" פירושו: להתאים בדיוק "n" פעמים. מכיוון שאנו מתאימים בדיוק "n" פעמים, "a{n}?"
שווה ל-"a{n}" והוא שם רק בשביל עקביות סימון.

הבה נסתכל על הדוגמה שלמעלה, אך עם מכמתים מינימליים:

$x = "רפובליקת התכנות של פרל";
$x =~ /^(.+?)(e|r)(.*)$/; # התאמות,
# $1 = 'ה'
# $2 = 'e'
# $3 = ' רפובליקת התכנות של פרל'

המחרוזת המינימלית שתאפשר גם את התחלת המחרוזת "^" וגם את ההחלפה ל
ההתאמה היא "Th", כאשר החלופה "e|r" תואמת ל-e. הכמת השני ".*" הוא
חופשי לזלול את שאר המחרוזת.

$x =~ /(m{1,2}?)(.*?)$/; # התאמות,
# $1 = 'm'
# $2 = 'רפובליקת מינג של פרל'

מיקום המחרוזת הראשון שהביטוי הרגולרי הזה יכול להתאים הוא ב-'m' הראשון ב"תכנות".
במיקום זה, ה-"m{1,2}" המינימלי? תואם רק 'מ' אחד. למרות השני
מכמת ".*?" מעדיף לא להתאים שום תווים, זה מוגבל על ידי סוף-
מחרוזת עוגן "$" כדי להתאים לשאר המחרוזת.

$x =~ /(.*?)(m{1,2}?)(.*)$/; # התאמות,
# $1 = 'התוכנית'
# $2 = 'm'
# $3 = 'רפובליקת מינג של פרל'

בביטוי הרגולרי הזה, אתה עשוי לצפות לכמת המינימלי הראשון ".*?" כדי להתאים לריק
מחרוזת, מכיוון שהיא אינה מוגבלת על ידי עוגן "^" כדי להתאים לתחילת המילה.
עם זאת, עיקרון 0 חל כאן. כי זה אפשרי לכל הביטוי הרגולרי להתאים
בתחילת המחרוזת, זה יצטרך התאמה בתחילת המחרוזת. כך הראשון
מכמת צריך להתאים הכל ל-m הראשון. המכמת המינימלי השני
תואם רק "מ" אחד והכמת השלישי מתאים לשאר המחרוזת.

$x =~ /(.??)(m{1,2})(.*)$/; # התאמות,
# $1 = 'a'
# $2 = 'ממ'
# $3 = 'הרפובליקה של פרל'

בדיוק כמו בביטוי הרגולרי הקודם, המכמת הראשון ".??" יכול להתאים הכי מוקדם בעמדה
'א', אז זה קורה. הכמת השני הוא חמדן, אז הוא מתאים ל"מ"מ", והשלישי
תואם את שאר המחרוזת.

אנו יכולים לשנות את עיקרון 3 לעיל כדי לקחת בחשבון כימים שאינם חמדנים:

· עקרון 3: אם יש שני אלמנטים או יותר בביטוי רגולרי, החמדן השמאלי ביותר (לא-
greedy) quantifier, אם בכלל, יתאים לכמה שיותר (מעט) מהמחרוזת
תוך שהוא מאפשר לכל הביטוי הרגולרי להתאים. החמדן הבא השמאלי ביותר (לא חמדן)
quantifier, אם בכלל, ינסה להתאים כמה (מעט) מהמחרוזת שנותרה
זמין לו ככל האפשר, תוך שהוא מאפשר לכל הביטוי הרגולרי להתאים. וכך
פועל, עד שכל רכיבי הביטוי הרגולרי מסופקים.

בדיוק כמו לחילופין, מכמים גם רגישים לחזרה לאחור. הנה שלב-
ניתוח שלב של הדוגמה

$x = "החתול בכובע";
$x =~ /^(.*)(at)(.*)$/; # התאמות,
# $1 = 'החתול ב-h'
# $2 = 'ב'
# $3 = '' (0 התאמות)

0 התחל עם האות הראשונה במחרוזת 't'.

1 הכמת הראשון '.*' מתחיל בהתאמת המחרוזת כולה 'החתול ב-
כּוֹבַע'.

2 'a' באלמנט regexp 'at' אינו תואם לקצה המחרוזת. חזרה אחת
אופי.

3 'a' באלמנט regexp 'at' עדיין לא תואם את האות האחרונה של המחרוזת 't',
אז חזור אחורה של דמות אחת נוספת.

4 כעת נוכל להתאים את ה-a וה-t.

5 עברו לרכיב השלישי '.*'. מכיוון שאנו נמצאים בסוף המחרוזת ו-'.*' יכול
להתאים 0 פעמים, הקצה לו את המחרוזת הריקה.

6 סיימנו!

רוב הזמן, כל התנועה קדימה והחזרה לאחור מתרחשת במהירות ובחיפוש
מהיר. עם זאת, ישנם כמה ביטויים מחודשים פתולוגיים, שזמן הביצוע שלהם אקספוננציאלי
גדל עם גודל החוט. מבנה טיפוסי שמתפוצץ לך בפנים הוא של
הצורה

/(a|b+)*/;

הבעיה היא המכמים הבלתי מוגדרים המקוננים. יש הרבה דרכים שונות של
חלוקת מחרוזת באורך n בין ה-"+" ל-"*": חזרה אחת עם "b+" של
אורך n, שתי חזרות עם הראשון "b+" באורך k והשני באורך nk, m
חזרות שהסיביות שלהן מסתכמות באורך n וכו'. למעשה יש מספר אקספוננציאלי
של דרכים לחלק מחרוזת כפונקציה של אורכה. ביטוי מחודש עשוי להתמזל מזלו ו
התאמה בשלב מוקדם של התהליך, אך אם אין התאמה, פרל תנסה כל אפשרות
לפני הוויתור. אז היזהר עם סימני "*", "{n,m}" ו-"+" מקוננים. הספר
מאסטרינג רגיל ביטויים מאת ג'פרי פרידל נותן דיון נפלא על זה ו
בעיות יעילות אחרות.

קַנָאִי כימות
החזרה לאחור במהלך החיפוש הבלתי פוסק אחר התאמה עשויה להיות בזבוז זמן, במיוחד
כאשר המשחק צפוי להיכשל. שקול את הדפוס הפשוט

/^\w+\s+\w+$/; # מילה, רווחים, מילה

בכל פעם שהדבר מוחל על מחרוזת שלא לגמרי עונה על הציפיות של הדפוס
כגון "abc" או "abc def", מנוע ה-Rexex יחזור אחורה, בערך פעם אחת
כל תו במחרוזת. אבל אנחנו יודעים שאין דרך לעקוף לקחת את כל של
תווי מילה ראשוניים שיתאימו לחזרה הראשונה, זה את כל חללים חייבים להיאכל על ידי
החלק האמצעי, וכך גם לגבי המילה השנייה.

עם כניסתה של ה- ברכושנות כימות ב-Perl 5.10, יש לנו דרך
מורה למנוע הרקסים לא לחזור אחורה, עם המכמים הרגילים עם "+"
צורף אליהם. זה הופך אותם לחמדנים וגם לקמצנים; ברגע שהם יצליחו הם לא יצליחו
להחזיר כל דבר כדי לאפשר פתרון אחר. יש להם את המשמעויות הבאות:

· "a{n,m}+" פירושו: התאם לפחות "n" פעמים, לא יותר מ-"m" פעמים, כמה פעמים
אפשרי, ואל תוותר על שום דבר. "a?+" הוא קיצור של "a{0,1}+"

· "a{n,}+" פירושו: להתאים לפחות "n" פעמים, אבל כמה פעמים שאפשר, ואל תתאים
לוותר על כל דבר. "a*+" הוא קיצור של "a{0,}+" ו-"a++" הוא קיצור של "a{1,}+".

· "a{n}+" פירושו: להתאים בדיוק "n" פעמים. זה רק שם בשביל עקביות סימון.

מכמים רכושניים אלה מייצגים מקרה מיוחד של מושג כללי יותר, ה
עצמאי ביטוי יתר, ראה למטה.

כדוגמה שבה מתאים כימת רכושנית אנו שוקלים התאמת ציטוט
מחרוזת, כפי שהיא מופיעה במספר שפות תכנות. הנטוי האחורי משמש כ-
דמות בריחה שמציינת שהדמות הבאה צריכה להילקח מילולית, כמו
תו נוסף למחרוזת. לכן, לאחר ציטוט הפתיחה, אנו מצפים ל-
(אולי ריק) רצף של חלופות: או דמות כלשהי מלבד ציטוט שלא נמלט
או קו נטוי אחורי או דמות נמלטת.

/"(?:[^"\\]++|\\.)*+"/;

בִּניָן a regexp
בשלב זה, יש לנו את כל המושגים הבסיסיים של הביטוי הרגולרי, אז בואו ניתן עוד
דוגמה מעורבת של ביטוי רגולרי. נבנה ביטוי מחודש שמתאים למספרים.

המשימה הראשונה בבניית regexp היא להחליט מה אנחנו רוצים להתאים ומה אנחנו רוצים
לא לכלול. במקרה שלנו, אנחנו רוצים להתאים גם מספרים שלמים וגם מספרי נקודה צפה ואנחנו
רוצה לדחות כל מחרוזת שאינה מספר.

המשימה הבאה היא לפרק את הבעיה לבעיות קטנות יותר המומרות בקלות
לתוך ביטוי רגולרי.

המקרה הפשוט ביותר הוא מספרים שלמים. אלה מורכבים מרצף של ספרות, עם אופציונלי
לחתום מלפנים. הספרות שאנו יכולים לייצג עם "\d+" ואת הסימן ניתן להתאים
"[+-]". לפיכך הביטוי הרגולרי של המספר השלם הוא

/[+-]?\d+/; # תואם מספרים שלמים

למספר נקודה צפה יש אולי סימן, חלק אינטגרלי, נקודה עשרונית, א
חלק שבר, ומעריך. אחד או יותר מהחלקים האלה הם אופציונליים, אז אנחנו צריכים
לבדוק את האפשרויות השונות. מספרי נקודה צפה שנמצאים בצורה נכונה
כוללים 123., 0.345, .34, -1e6 ו-25.4E-72. כמו עם מספרים שלמים, השלט בחוץ הוא
אופציונלי לחלוטין וניתן להתאים אותו באמצעות "[+-]?". אנחנו יכולים לראות שאם אין
מעריך, מספרי נקודה צפה חייבים להיות בנקודה עשרונית, אחרת הם מספרים שלמים.
אנו עשויים להתפתות לדגמן אלה עם "\d*\.\d*", אבל זה גם יתאים רק ל-a
נקודה עשרונית בודדת, שאינה מספר. אז שלושת המקרים של מספר נקודה צפה
ללא אקספוננט הם

/[+-]?\d+\./; # 1., 321. וכו'.
/[+-]?\.\d+/; # .1, .234 וכו'.
/[+-]?\d+\.\d+/; # 1.0, 30.56 וכו'.

ניתן לשלב את אלה לביטוי רגולרי יחיד עם חילופין תלת כיווני:

/[+-]?(\d+\.\d+|\d+\.|\.\d+)/; # נקודה צפה, ללא מעריך

בחילופין זה, חשוב לשים '\d+\.\d+' לפני '\d+\.'. אם '\d+\.' היו
ראשית, הביטוי הרגולרי יתאים לזה בשמחה ויתעלם מהחלק השברי של המספר.

עכשיו שקול מספרי נקודה צפה עם מעריכים. התצפית המרכזית כאן היא זו שניהם
מספרים שלמים ומספרים עם נקודות עשרוניות מותרים מול מעריך. לאחר מכן
אקספוננטים, כמו הסימן הכולל, אינם תלויים בשאלה האם אנו מתאימים מספרים עם
או ללא נקודות עשרוניות, וניתן 'לנתק' מהמנטיסה. הצורה הכוללת של
הביטוי הרגולרי מתברר כעת:

/^(סימן אופציונלי)(מספר שלם | fp mantissa)(מעריך אופציונלי)$/;

המעריך הוא "e" או "E", ואחריו מספר שלם. אז האקספונט הרגולרי הוא

/[eE][+-]?\d+/; # מעריך

אם נחבר את כל החלקים יחד, נקבל ביטוי רגולרי שמתאים למספרים:

/^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/; # טא דה!

ביטויים חוזרים ארוכים כמו זה עשויים להרשים את החברים שלך, אבל יכול להיות קשה לפענח. במתחם
במצבים כמו זה, השינוי "//x" עבור התאמה הוא בעל ערך רב. זה מאפשר לשים
רווח לבן כמעט שרירותי והערות לביטוי רגולרי מבלי להשפיע על המשמעות שלהם.
באמצעותו, נוכל לכתוב מחדש את הביטוי הרגולרי 'המורחב' שלנו בצורה הנעים יותר

/^
[+-]? # ראשית, התאם סימן אופציונלי
(# ואז התאם מספרים שלמים או שלמה ל-fp:
\d+\.\d+ # mantissa של הצורה ab
|\d+\. # מנטיסה של הצורה א.
|\.\d+ # מנטיסה של הצורה .ב
|\d+ # מספר שלם מהצורה a
)
([eE][+-]?\d+)? # לבסוף, אופציונלי להתאים מעריך
$/x;

אם הרווח הלבן לרוב לא רלוונטי, איך אפשר לכלול תווי רווח ברחבה
ביטוי רגיל? התשובה היא לחתוך אותו '\ ' או לשים אותו במחלקה של תווים "[ ]". אותו הדבר
הדבר מתאים לסימני פאונד: השתמש ב-"\#" או "[#]". לדוגמה, Perl מאפשר רווח בין
הסימן והמנטיסה או המספר השלם, ונוכל להוסיף את זה לביטוי הרגולרי שלנו באופן הבא:

/^
[+-]?\ * # ראשית, התאם סימן אופציונלי *ורווח*
(# ואז התאם מספרים שלמים או שלמה ל-fp:
\d+\.\d+ # mantissa של הצורה ab
|\d+\. # מנטיסה של הצורה א.
|\.\d+ # מנטיסה של הצורה .ב
|\d+ # מספר שלם מהצורה a
)
([eE][+-]?\d+)? # לבסוף, אופציונלי להתאים מעריך
$/x;

בצורה זו, קל יותר לראות דרך לפשט את החלופה. חלופות 1, 2,
ו-4 כולם מתחילים ב-"\d+", כך שניתן יהיה למנות אותם:

/^
[+-]?\ * # ראשית, התאם סימן אופציונלי
(# ואז התאם מספרים שלמים או שלמה ל-fp:
\d+ # התחל עם ...
(
\.\d* # מנטיסה מהצורה ab או a.
)? #? דואג למספרים שלמים מהצורה א
|\.\d+ # מנטיסה של הצורה .ב
)
([eE][+-]?\d+)? # לבסוף, אופציונלי להתאים מעריך
$/x;

או כתוב בצורה קומפקטית,

/^[+-]?\ *(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;

זה הביטוי הרגולרי האחרון שלנו. לסיכום, בנינו ביטוי מחודש על ידי

· ציון המשימה בפירוט,

· פירוק הבעיה לחלקים קטנים יותר,

· תרגום החלקים הקטנים לביטויים חוזרים,

· שילוב של הביטויים הרגולריים,

· ואופטימיזציה של הביטוי הרגולרי המשולב הסופי.

אלו הם גם השלבים האופייניים הכרוכים בכתיבת תוכנת מחשב. זה עושה
הגיוני לחלוטין, כי ביטויים רגולריים הם בעצם תוכניות שנכתבו במעט
שפת מחשב המפרטת דפוסים.

שימוש רגיל ביטויים in פרל
הנושא האחרון של חלק 1 מכסה בקצרה כיצד נעשה שימוש בביטויים רגועים בתוכניות Perl. איפה לעשות
הם מתאימים לתחביר פרל?

כבר הצגנו את אופרטור ההתאמה ברירת המחדל שלו "/regexp/" ושרירותית
מפריד "m!regexp!" טפסים. השתמשנו באופרטור המחייב "=~" ושלילתו "!~"
כדי לבדוק התאמות מיתר. משויך לאופרטור ההתאמה, דנו ב-
שורה בודדת "//s", מרובה שורות "//m", "//i" בלתי תלויה באותיות רישיות ו-"//x" מורחבים.
יש עוד כמה דברים שאולי תרצה לדעת על התאמת אופרטורים.

אוסר החלפה

אם תשנה $pattern לאחר ההחלפה הראשונה, Perl תתעלם מזה. אם אתה
לא רוצה תחליפים בכלל, השתמש במפריד המיוחד "m''":

@pattern = ('Seuss');
בעוד (<>) {
הדפס אם m'@pattern'; # תואם את המילולי '@pattern', לא 'Seuss'
}

בדומה למחרוזות, "m''" פועל כמו אפוסטרופים על ביטוי רגוע; כל שאר תוחמי "m" פועלים
כמו ציטוטים. אם ה-Regexp מוערך למחרוזת הריקה, ה-Regexp ב- אחרון
מוצלח להתאים משמש במקום זאת. אז יש לנו

"כלב" =~ /d/; # התאמות 'd'
"dogbert =~ //; # זה תואם לביטוי הרגולרי 'd' ששימש קודם

גלוֹבָּלִי תואם

שני המשתנים האחרונים עליהם נדון כאן, "//g" ו-"//c", נוגעים למספר התאמות.
המשנה "//g" מייצג התאמה גלובלית ומאפשר לאופרטור ההתאמה להתאים
בתוך מחרוזת כמה שיותר פעמים. בהקשר סקלרי, קריאות עוקבות
נגד מיתר יהיה "//g" קפיצה מגפרור לגפרור, תוך מעקב אחר המיקום
המיתר תוך כדי. אתה יכול לקבל או להגדיר את המיקום עם הפונקציה "pos()".

השימוש ב-"//g" מוצג בדוגמה הבאה. נניח שיש לנו מחרוזת ש
מורכב ממילים המופרדות ברווחים. אם אנחנו יודעים כמה מילים יש מראש, אנחנו
יכול לחלץ את המילים באמצעות קבוצות:

$x = "בית כלב חתול"; # 3 מילים
$x =~ /^\s*(\w+)\s+(\w+)\s+(\w+)\s*$/; # התאמות,
# $1 = 'חתול'
# $2 = 'כלב'
# $3 = 'בית'

אבל מה אם היה לנו מספר בלתי מוגדר של מילים? זה סוג המשימה "//g" הייתה
הוכן בשביל. כדי לחלץ את כל המילים, צור את הביטוי הרגולרי הפשוט "(\w+)" ולופ על כל ההתאמות
עם "/(\w+)/g":

while ($x =~ /(\w+)/g) {
print "המילה היא $1, מסתיימת בעמדה ", pos $x, "\n";
}

הדפסים

המילה היא חתול, מסתיימת בעמדה 3
המילה היא כלב, מסתיימת בעמדה 7
המילה היא בית, מסתיימת בעמדה 13

התאמה נכשלה או שינוי מחרוזת היעד מאפסים את המיקום. אם אתה לא רוצה את
איפוס המיקום לאחר אי התאמה, הוסף את ה-"//c", כמו ב-"/regexp/gc". הנוכחי
המיקום במחרוזת משויך למחרוזת, לא לביטוי הרגולרי. זה אומר ש
למחרוזות שונות יש מיקומים שונים וניתן להגדיר את המיקומים בהתאמה או
לקרוא באופן עצמאי.

בהקשר של רשימה, "//g" מחזיר רשימה של קבוצות מותאמות, או אם אין קיבוץ,
רשימה של התאמות לכל הביטוי הרגולרי. אז אם היינו רוצים רק את המילים, נוכל להשתמש

@words = ($x =~ /(\w+)/g); # התאמות,
# $words[0] = 'חתול'
# $words[1] = 'כלב'
# $words[2] = 'בית'

קשור קשר הדוק למשנה "//g" הוא עוגן "\G". העוגן "\G" תואם ב-
הנקודה שבה הפסיקה ההתאמה "//g" הקודמת. "\G" מאפשר לנו לעשות בקלות הקשר-
התאמה רגישה:

$metric = 1; # השתמש ביחידות מטריות
...
$x = ; # קרא במדידה
$x =~ /^([+-]?\d+)\s*/g; # לקבל גודל
$weight = $1;
if ($metric) { # בדיקת שגיאה
הדפס "שגיאת יחידות!" אלא אם כן $x =~ /\Gkg\./g;
}
אחר {
הדפס "שגיאת יחידות!" אלא אם כן $x =~ /\Glbs\./g;
}
$x =~ /\G\s+(widget|sprocket)/g; # המשך בעיבוד

השילוב של "//g" ו-"\G" מאפשר לנו לעבד את המחרוזת קצת בכל פעם ולהשתמש
היגיון שרירותי של Perl כדי להחליט מה לעשות הלאה. נכון לעכשיו, העוגן "\G" מלא רק
נתמך כאשר משתמשים בו לעיגון לתחילת התבנית.

"\G" הוא גם בעל ערך רב בעיבוד רשומות באורך קבוע עם ביטויים רגועים. נניח שיש לנו
קטע של DNA של אזור קידוד, מקודד בתור אותיות זוג בסיסים "ATCGTTGAAT..." ואנחנו רוצים
כדי למצוא את כל קודוני העצירה "TGA". באזור מקודד, קודונים הם רצפים בני 3 אותיות, אז
אנו יכולים לחשוב על קטע ה-DNA כרצף של רשומות של 3 אותיות. הביטוי הרגולרי הנאיבי

# מורחב, זה "ATC GTT GAA TGC AAA TGA CAT GAC"
$dna = "ATCGTTGAATGCAAATGACATGAC";
$dna =~ /TGA/;

לא עובד; זה עשוי להתאים ל"TGA", אבל אין ערובה שההתאמה מיושרת
עם גבולות קודון, למשל, המחרוזת המשנה "GTT GAA" נותנת התאמה. פתרון טוב יותר הוא

while ($dna =~ /(\w\w\w)*?TGA/g) { # שימו לב ל-* המינימלי?
print "יש לי קודון עצירה של TGA בעמדה ", pos $dna, "\n";
}

שמדפיס

יש קודון עצירה של TGA בעמדה 18
יש קודון עצירה של TGA בעמדה 23

עמדה 18 טובה, אבל עמדה 23 מזויפת. מה קרה?

התשובה היא שהביטוי הרגולרי שלנו עובד היטב עד שנעבור את ההתאמה האמיתית האחרונה. אז ה
regexp לא יצליח להתאים ל-"TGA" מסונכרן ויתחיל לצעוד דמות אחת קדימה
מיקום בכל פעם, לא מה שאנחנו רוצים. הפתרון הוא להשתמש ב-"\G" כדי לעגן אליו את ההתאמה
יישור הקודון:

while ($dna =~ /\G(\w\w\w)*?TGA/g) {
print "יש לי קודון עצירה של TGA בעמדה ", pos $dna, "\n";
}

זה מודפס

יש קודון עצירה של TGA בעמדה 18

שזו התשובה הנכונה. דוגמה זו ממחישה שחשוב לא רק
להתאים את הרצוי, אבל לדחות את מה שלא רצוי.

(ישנם מתקנים אחרים של הביטוי הרגולרי הזמינים, כגון "//o", אך הם מיוחדים
השימושים הם מעבר להיקף של מבוא זה. )

חיפוש ו להחליף

גם לביטויים רגולריים יש תפקיד גדול search ו להחליף פעולות בפרל. לחפש
והחלפה מתבצעת עם האופרטור "s///". הצורה הכללית היא
"s/regexp/replacement/modifiers", עם כל מה שאנחנו יודעים על regexps ו-modifiers
חלים גם במקרה זה. ה"החלפה" היא מחרוזת פרל במירכאות כפולות
מחליף במחרוזת כל מה שמתאים ל-"regexp". האופרטור "=~" הוא גם
משמש כאן כדי לשייך מחרוזת ל-"s///". אם מתאימים נגד $_, ה-"$_ =~" יכול להיות
ירד. אם יש התאמה, "s///" מחזיר את מספר ההחלפות שבוצעו; אחרת
זה מחזיר false. הנה כמה דוגמאות:

$x = "הגיע הזמן להאכיל את החתול!";
$x =~ s/cat/hacker/; # $x מכיל "זמן להאכיל את ההאקר!"
if ($x =~ s/^(Time.*hacker)!$/$1 עכשיו!/) {
$more_insistent = 1;
}
$y = "'מילים מובאות'";
$y =~ s/^'(.*)'$/$1/; # רצועת מרכאות בודדות,
# $y מכיל "מילים מובאות"

בדוגמה האחרונה, כל המיתר תואם, אבל רק החלק שבתוך הסינגל
ציטוטים היו מקובצים. עם האופרטור "s///", המשתנים התואמים $1, $2 וכו' הם
זמין באופן מיידי לשימוש בביטוי ההחלפה, אז אנו משתמשים ב-$1 כדי להחליף את
מחרוזת מצוטטת רק עם מה שצוטט. עם השינוי הגלובלי, "s///g" יחפש
והחלף את כל המופעים של הביטוי הרגולרי במחרוזת:

$x = "חבטתי 4 עבור 4";
$x =~ s/4/four/; # לא עושה הכל:
# $x מכיל "חבטתי ארבע עבור 4"
$x = "חבטתי 4 עבור 4";
$x =~ s/4/four/g; # עושה הכל:
# $x מכיל "חבטתי ארבע עבור ארבע"

אם אתה מעדיף 'regex' על 'regexp' במדריך זה, תוכל להשתמש בתוכנית הבאה
להחליף אותו:

% cat > simple_replace
#!/usr/bin/perl
$regexp = shift;
$replacement = shift;
בעוד (<>) {
s/$regexp/$replacement/g;
הדפס;
}
^D

% simple_replace regexp regex perlretut.pod

ב-"simple_replace" השתמשנו במשנה "s///g" כדי להחליף את כל המופעים של הביטוי הרגולרי
על כל שורה. (למרות שהביטוי הרגולרי מופיע בלולאה, Perl מספיק חכמה
לקמפל אותו רק פעם אחת.) כמו ב-"simple_grep", גם ה-"print" וגם ה-
"s/$regexp/$replacement/g" השתמש ב-$_ באופן מרומז.

אם אתה לא רוצה ש-"s///" ישנה את המשתנה המקורי שלך, אתה יכול להשתמש ב-non-destructive
תחליף משנה, "s///r". זה משנה את ההתנהגות כך ש"s///r" מחזיר את הגמר
מחרוזת מוחלפת (במקום מספר ההחלפות):

$x = "אני אוהב כלבים.";
$y = $x =~ s/dogs/cats/r;
הדפס "$x $y\n";

הדוגמה הזו תדפיס "אני אוהב כלבים. אני אוהב חתולים". שימו לב למשתנה $x המקורי יש
לא הושפע. התוצאה הכוללת של ההחלפה מאוחסנת במקום זאת ב-$y. אם ה
החלפה לא משפיעה על כלום אז המחרוזת המקורית מוחזרת:

$x = "אני אוהב כלבים.";
$y = $x =~ s/פילים/פומות/ר;
הדפס "$x $y\n"; # prints "אני אוהב כלבים. אני אוהב כלבים."

דבר מעניין נוסף שדגל "s///r" מאפשר הוא שרשור תחליפים:

$x = "חתולים הם נהדרים.";
הדפס $x =~ s/חתולים/כלבים/ר =~ s/כלבים/צפרדעים/ר =~
s/Frogs/Hedgehogs/r, "\n";
# הדפסים "קיפודים הם נהדרים."

שינוי זמין במיוחד לחיפוש והחלפה הוא הערכת "s///e".
מַתקֵן. "s///e" מתייחס לטקסט החלופי כקוד Perl, במקום מרכאות כפולות
חוּט. הערך שהקוד מחזיר מוחלף במחרוזת המשנה התואמת.
"s///e" שימושי אם אתה צריך לעשות קצת חישוב בתהליך של החלפת טקסט.
דוגמה זו סופרת את תדרי התווים בשורה:

$x = "תחייב את החתול";
$x =~ s/(.)/$chars{$1}++;$1/למשל; # $1 אחרון מחליף את ה-char בעצמו
הדפס "תדירות של '$_' היא $chars{$_}\n"
foreach (מיין {$chars{$b} <=> $chars{$a}} מפתחות %chars);

זה מודפס

התדירות של ' ' היא 2
התדירות של 't' היא 2
התדירות של 'l' היא 2
התדירות של 'B' היא 1
התדירות של 'c' היא 1
התדירות של 'e' היא 1
התדירות של 'h' היא 1
התדירות של 'i' היא 1
התדירות של 'a' היא 1

בדומה לאופרטור ההתאמה "m//", "s///" יכול להשתמש במפרידים אחרים, כגון "s!!!" ו
"s{}{}", ואפילו "s{}//". אם משתמשים במרכאות בודדות "s'''", אז הביטוי הרגולרי ו
ההחלפה מטופלת כמחרוזות במירכאות בודדות ואין החלפות משתנות.
"s///" בהקשר רשימה מחזיר את אותו הדבר כמו בהקשר סקלארי, כלומר, מספר
גפרורים.

השמיים לפצל פונקציה

הפונקציה "split()" היא מקום נוסף שבו נעשה שימוש ב-Regexp. "פיצול /regexp/, מחרוזת,
limit" מפריד את האופרנד "מחרוזת" לרשימה של מחרוזות משנה ומחזיר רשימה זו.
הביטוי הרגולרי חייב להיות מתוכנן כך שיתאים לכל מה שמהווה את המפרידים לרצוי
מחרוזות משנה. ה"גבול", אם קיים, מגביל את הפיצול ללא יותר מ"גבול"
מספר מחרוזות. לדוגמה, כדי לפצל מחרוזת למילים, השתמש

$x = "קלווין והובס";
@words = פיצול /\s+/, $x; # $word[0] = 'קלווין'
# $word[1] = 'ו'
# $word[2] = 'הובים'

אם נעשה שימוש ב-Regexp הריק "//", ה-Regexp תמיד תואם והמחרוזת מפוצלת
דמויות בודדות. אם לביטוי הרגולרי יש קבוצות, אז הרשימה המתקבלת מכילה את
תת-מחרוזות תואמות גם מהקבוצות. לדוגמה,

$x = "/usr/bin/perl";
@dirs = פיצול m!/!, $x; # $dirs[0] = ''
# $dirs[1] = 'usr'
# $dirs[2] = 'bin'
# $dirs[3] = 'perl'
@parts = פיצול m!(/)!, $x; # $parts[0] = ''
# $parts[1] = '/'
# $parts[2] = 'usr'
# $parts[3] = '/'
# $parts[4] = 'פח'
# $parts[5] = '/'
# $parts[6] = 'perl'

מכיוון שהתו הראשון של $x תואם את הביטוי הרגולרי, "פיצול" הוסף ראשי תיבות ריק
רכיב לרשימה.

אם קראתם עד כאן, מזל טוב! כעת יש לך את כל הכלים הבסיסיים הדרושים לשימוש
ביטויים רגולריים כדי לפתור מגוון רחב של בעיות עיבוד טקסט. אם זה שלך
בפעם הראשונה במדריך, למה לא לעצור כאן ולשחק עם ביטויים רגועים א
בעוד... חלק 2 נוגע להיבטים האזוטריים יותר של ביטויים רגולריים ואלו
מושגים בהחלט לא נחוצים כבר בהתחלה.

חלק 2: כוח כלים


בסדר, אתה יודע את היסודות של ביטויים רגועים ואתה רוצה לדעת יותר. אם תואם רגיל
ביטויים מקבילים לטיול ביער, אז הכלים הנדונים בחלק 1 הם
בדומה למפות טופו ומצפן, כלים בסיסיים שאנו משתמשים בהם כל הזמן. רוב הכלים
בחלק 2 מקבילים לרובי התלקחות וטלפונים לווייניים. הם לא משמשים לעתים קרובות מדי על
טיול רגלי, אבל כשאנחנו תקועים, הם יכולים להיות לא יסולא בפז.

להלן היכולות המתקדמות יותר, הפחות בשימוש, או לפעמים אזוטריות של Perl
ביטויים רגועים. בחלק 2, נניח שאתה מרגיש בנוח עם היסודות ולהתרכז בהם
התכונות המתקדמות.

עוד on תווים, מחרוזות, ו אופי כיתות
ישנם מספר רצפי בריחה ושיעורי דמות שעדיין לא סיקרנו.

ישנם מספר רצפי בריחה הממירים תווים או מחרוזות בין עליון ל
אותיות קטנות, והם זמינים גם בתוך דפוסים. "\l" ו-"\u" ממירים את הבא
תו לאותיות קטנות או גדולות, בהתאמה:

$x = "perl";
$string =~ /\u$x/; # תואם את 'Perl' ב-$string
$x = "M(rs?|s)\\."; # שימו לב לאחור הכפול
$string =~ /\l$x/; # מתאים ל-'mr.', 'mrs.', ו-'ms.',

"\L" או "\U" מציינים המרה מתמשכת של מקרה, עד לסיום על ידי "\E" או לזרוק
על ידי "\U" או "\L" אחר:

$x = "מילה זו היא באותיות קטנות:\L SHOUT\E";
$x =~ /צעקה/; # התאמות
$x = "אני עדיין כרטיסי לחיצה על ה-360 שלי"
$x =~ /\Ukeypunch/; # תואם מחרוזת כרטיסי ניקוב

אם אין "\E", האותיות מומרות עד סוף המחרוזת. הביטויים הרגולריים
"\L\u$word" או "\u\L$word" ממירים את התו הראשון של $word לאותיות רישיות והשאר
של התווים לאותיות קטנות.

ניתן להמלט תווי שליטה עם "\c", כך שתו של שליטה-Z יהיה
תואם עם "\cZ". רצף הבריחה "\Q"..."\E" מצטט, או מגן על רוב הלא-
תווים אלפביתיים. לדוגמה,

$x = "\QThat !^*&%~& חתול!";
$x =~ /\Q!^*&%~&\E/; # בדוק אם יש שפה גסה

זה לא מגן על "$" או "@", כך שעדיין ניתן להחליף משתנים.

"\Q", "\L", "\l", "\U", "\u" ו-"\E" הם למעשה חלק מתחביר מרשושיות כפולות, ולא
חלק מתחביר הביטוי הרגולרי הנכון. הם יעבדו אם הם יופיעו בביטוי רגולרי
מוטמע ישירות בתוכנית, אך לא כאשר הוא נכלל במחרוזת המשולבת ב
תבנית.

הביטויים הרגולריים של Perl יכולים להתמודד עם יותר מסתם מערך התווים הסטנדרטי של ASCII. פרל תומכת
Unicode, תקן לייצוג האלפבית כמעט מכל העולם
שפות כתובות, ושלל סמלים. מחרוזות הטקסט של Perl הן מחרוזות Unicode, אז
הם יכולים להכיל תווים עם ערך (נקודת קוד או מספר תו) גבוה מ-255.

מה זה אומר על ביטויים רגועים? ובכן, משתמשי regexp לא צריכים לדעת הרבה על Perl's
ייצוג פנימי של מיתרים. אבל הם צריכים לדעת 1) איך לייצג את יוניקוד
תווים ב-Regexp ו-2) שפעולת התאמה תתייחס למחרוזת להיות
חיפשו כרצף של תווים, לא בתים. התשובה ל-1) היא כי Unicode
דמויות גדולות מ"chr(255)" מיוצגים באמצעות הסימון "\x{hex}", כי
\x hex (ללא סוגרים מסולסלים) לא עובר יותר מ-255. (החל ב-Perl 5.14, אם
אתה אוהד אוקטלי, אתה יכול גם להשתמש ב-"\o{oct}".)

/\x{263a}/; # התאם פרצוף סמיילי של יוניקוד :)

הערה: ב-Perl 5.6.0 פעם היה צריך לומר "השתמש ב-utf8" כדי להשתמש בכל Unicode
מאפיינים. זה כבר לא המקרה: כמעט בכל עיבוד Unicode, המפורש
אין צורך בפרגמה "utf8". (המקרה היחיד שבו זה משנה הוא אם הסקריפט של Perl שלך נמצא
Unicode ומקודד ב-UTF-8, אז יש צורך ב"שימוש ב-utf8" מפורש.)

להבין את הרצף ההקסדצימלי של תו Unicode שאתה רוצה או לפענח
הביטוי הרגולרי של Unicode ההקסדצימלי של מישהו אחר הוא מהנה בערך כמו תכנות במכונה
קוד. אז דרך נוספת לציין תווי Unicode היא להשתמש ב- בשם אופי לברוח
רצף "\N{שֵׁם}". שם הוא שם לתו Unicode, כפי שצוין ב-
תקן יוניקוד. למשל, אם נרצה לייצג או להתאים את המזל האסטרולוגי
עבור כוכב הלכת מרקורי, נוכל להשתמש

$x = "abc\N{MERCURY}def";
$x =~ /\N{MERCURY}/; # התאמות

אפשר גם להשתמש בשמות "קצרים":

הדפס "\N{GREEK SMALL LETTER SIGMA} נקראת sigma.\n";
print "\N{greek:Sigma} הוא סיגמא באותיות גדולות.\n";

אתה יכול גם להגביל שמות לאלפבית מסוים על ידי ציון פרגמת השמות:

השתמש ב-charnames qw(יוונית);
הדפס "\N{sigma} הוא סיגמא יוונית\n";

אינדקס של שמות תווים זמין מקוון מ-Unicode Consortium,
<http://www.unicode.org/charts/charindex.html>; חומר הסבר עם קישורים לאחרים
משאבים בhttp://www.unicode.org/standard/where>.

התשובה לדרישה 2) היא ש-Regexp (בעיקר) משתמש בתווי Unicode. ה
"לרוב" זה מסיבות מבולגנות של תאימות לאחור, אבל החל מ-Perl 5.14, כל ביטוי רגולרי
הידור בהיקף של "שימוש בתכונה 'unicode_strings'" (שהופכת אוטומטית
בטווח של "שימוש ב-5.012" ומעלה) יהפוך את זה "לרוב" ל"תמיד". אם
ברצונך לטפל ב-Unicode כראוי, עליך לוודא שה-'unicode_strings' הופכת
עַל. באופן פנימי, זה מקודד לבייטים באמצעות UTF-8 או קידוד מקורי של 8 סיביות,
תלוי בהיסטוריה של המחרוזת, אבל מבחינה רעיונית זה רצף של תווים,
לא בתים. ראה perlunitut להדרכה בנושא.

הבה נדון כעת במחלקות תווים של Unicode, הנקראות לרוב "מאפייני תווים".
אלה מיוצגים על ידי רצף הבריחה "\p{name}". קשור קשר הדוק הוא
המאפיין "\P{name}", שהוא השלילה של ה-"\p{name}". למשל, להתאים
אותיות קטנות ורישיות,

$x = "BOB";
$x =~ /^\p{IsUpper}/; # התאמות, מחלקת תווים רישיות
$x =~ /^\P{IsUpper}/; # לא תואם, דרגת char ללא אותיות רישיות
$x =~ /^\p{IsLower}/; # לא תואם, מחלקת תווים קטנה
$x =~ /^\P{IsLower}/; # גפרורים, כיתת char ללא אותיות קטנות

(ה-"Is" הוא אופציונלי.)

יש הרבה מאוד מאפייני אופי Unicode. לרשימה המלאה ראה perluniprops.
לרובם יש מילים נרדפות עם שמות קצרים יותר, הרשומים גם שם. כמה מילים נרדפות הן א
דמות בודדת. עבור אלה, אתה יכול להוריד את הפלטה. לדוגמה, "\pM" זהה
דבר כמו "\p{Mark}", כלומר דברים כמו סימני הדגשה.

המאפיין Unicode "\p{Script}" משמש כדי לסווג כל תו Unicode ל-
כתב בשפה שבו הוא כתוב. לדוגמה, אנגלית, צרפתית ועוד המון דברים אחרים
שפות אירופה כתובות בכתב הלטיני. אבל יש גם את הכתב היווני,
התסריט התאילנדי, כתב הקטאקנה וכו'. ניתן לבדוק אם דמות נמצאת ב-a
סקריפט מסוים עם, למשל "\p{לטינית}", "\p{יוונית}", או "\p{Katakana}". לבחון
אם זה לא בסקריפט הבאלינזי, תשתמש ב-\P{Balinese}.

מה שתיארנו עד כה הוא הצורה הבודדת של מחלקות התווים "\p{...}".
יש גם צורה מורכבת שבה אתה עלול להיתקל. אלה נראים כמו "\p{name=value}" או
"\p{name:value}" (ניתן להשתמש בסימן השווה ובנקודתיים להחלפה). אלה יותר
כללית מאשר הצורה הבודדת, ולמעשה רוב הצורות הבודדות הן רק בהגדרת Perl
קיצורי דרך לצורות מורכבות נפוצות. לדוגמה, דוגמאות התסריט בקודם
הפסקה יכולה להיכתב באופן שווה ל-"\p{Script=Latin}", "\p{Script:Greek}",
"\p{script=katakana}", ו-"\P{script=balinese}" (המקרה אינו רלוונטי בין "{}"
פלטה). אולי לעולם לא תצטרך להשתמש בצורות המורכבות, אבל לפעמים זה הכרחי, ו
השימוש בהם יכול להפוך את הקוד שלך לקל יותר להבנה.

"\X" הוא קיצור של מחלקת תווים הכוללת Unicode מוּרחָב גרפמה
אשכול. זה מייצג "דמות הגיונית": מה שנראה כתו בודד,
אך עשוי להיות מיוצג פנימי על ידי יותר מאחד. כדוגמה, שימוש ב-Unicode מלא
שמות, למשל, "A + COMBINING RING" הוא אשכול גרפמה עם תו הבסיס "A" ו
שילוב תו "COMBINING RING", המתורגם בדנית ל-A עם העיגול למעלה
זה, כמו במילה Aangstrom.

למידע המלא והעדכני ביותר על Unicode ראה את תקן Unicode העדכני ביותר, או את
אתר האינטרנט של קונסורציום יוניקודhttp://www.unicode.org>

כאילו כל המחלקות האלה לא מספיקות, פרל גם מגדירה מחלקות דמויות בסגנון POSIX.
לאלה יש את הצורה "[:name:]", עם "שם" השם של מחלקת POSIX. ה-POSIX
הכיתות הן "אלפא", "אלnum", "ascii", "cntrl", "ספרה", "גרף", "נמוך", "הדפס",
"punct", "רווח", "upper" ו-"xdigit", ושתי הרחבות, "word" (הרחבה של Perl ל
להתאים את "\w"), ואת "ריק" (הרחבה של GNU). השינוי "//a" מגביל את אלה ל
התאמה רק בטווח ASCII; אחרת הם יכולים להתאים כמו המקבילים שלהם
מחלקות Perl Unicode: "[:upper:]" זהה ל-"\p{IsUpper}" וכו' (יש כמה
חריגים ותקלות עם זה; ראה perlrecharclass לדיון מלא.) The
"[:digit:]", "[:word:]", ו-"[:space:]" תואמות ל-"\d", "\w" ו-"\s" המוכרים
שיעורי אופי. כדי לשלול מחלקה POSIX, שים "^" לפני השם, כך,
למשל, "[:^digit:]" מתאים ל-"\D" ותחת Unicode, "\P{IsDigit}". Unicode ו
ניתן להשתמש במחלקות תו POSIX בדיוק כמו "\d", למעט POSIX
ניתן להשתמש במחלקות תווים רק בתוך מחלקת תווים:

/\s+[abc[:digit:]xyz]\s*/; # התאימו ל-a,b,c,x,y,z או ספרה
/^=item\s[[:ספרה:]]/; # match '=item',
# ואחריו רווח וספרה
/\s+[abc\p{IsDigit}xyz]\s+/; # התאימו ל-a,b,c,x,y,z או ספרה
/^=item\s\p{IsDigit}/; # match '=item',
# ואחריו רווח וספרה

וואו! זה כל שאר הדמויות ושיעורי הדמות.

קומפילציה ו חסכת רגיל ביטויים
בחלק 1 הזכרנו ש-Perl מרכיבה ביטוי רגולרי לרצף קומפקטי של קודים.
לפיכך, regexp מהול הוא מבנה נתונים שניתן לאחסן פעם אחת ולהשתמש בו שוב
שוב. הציטוט של הביטוי הרגולרי "qr//" עושה בדיוק את זה: "qr/string/" מרכיב את ה"מחרוזת" בתור
regexp והופך את התוצאה לצורה שניתן להקצות למשתנה:

$reg = qr/foo+bar?/; # reg מכיל ביטוי רגולרי מהול

אז ניתן להשתמש ב-$reg כביטוי רגולרי:

$x = "fooooba";
$x =~ $reg; # התאמות, בדיוק כמו /foo+bar?/
$x =~ /$reg/; # אותו דבר, צורה חלופית

ניתן לבצע אינטרפולציה של $reg לביטוי רגולרי גדול יותר:

$x =~ /(abc)?$reg/; # עדיין תואם

בדומה לאופרטור ההתאמה, הציטוט של הביטוי הרגולרי יכול להשתמש במפרידים שונים, למשל,
"qr!!", "qr{}" או "qr~~". אפוסתרפים כמפרידים ("qr''") מעכבים כל אינטרפולציה.

ביטויים רגולריים מהודרים מראש שימושיים ליצירת התאמות דינמיות שאינן צריכות להיות
הידור מחדש בכל פעם שהם נתקלים. באמצעות ביטויים רגועים שהורכבו מראש, אנו כותבים א
תוכנית "grep_step" אשר מבצעת grep עבור רצף של דפוסים, מתקדמת לדפוס הבא
ברגע שאדם היה מרוצה.

% cat > grep_step
#!/usr/bin/perl
# grep_step - התאמה ביטויים רגועים, אחד אחרי השני
# שימוש: multi_grep regexp1 regexp2 ... file1 file2 ...

$number = משמרת;
$regexp[$_] = shift foreach (0..$number-1);
@compiled = map qr/$_/, @regexp;
while ($line = <>) {
if ($line =~ /$compiled[0]/) {
הדפס $line;
shift @compiled;
אחרון אלא אם @קומpiled;
}
}
^D

% grep_step 3 shift הדפס grep_step אחרון
$number = משמרת;
הדפס $line;
אחרון אלא אם @קומpiled;

אחסון ביטויים רגועים שהורכבו מראש במערך @compiled מאפשר לנו פשוט לעבור דרך ה-
ביטויים רגועים ללא כל קומפילציה מחדש, ובכך משיגים גמישות מבלי להקריב מהירות.

מלחין רגיל ביטויים at זמן ריצה
החזרה לאחור יעילה יותר מניסיונות חוזרים ונשנים עם ביטויים רגולריים שונים. אם
יש כמה ביטויים רגולריים והתאמה לכל אחד מהם מקובלת, אז זה
אפשר לשלב אותם לסט של חלופות. אם הביטויים הבודדים הם
נתוני קלט, ניתן לעשות זאת על ידי תכנות פעולת הצטרפות. ננצל את הרעיון הזה
גרסה משופרת של תוכנית "simple_grep": תוכנית התואמת מרובים
דפוסים:

% cat > multi_grep
#!/usr/bin/perl
# multi_grep - התאמה לכל אחד ביטויים רגועים
# שימוש: multi_grep regexp1 regexp2 ... file1 file2 ...

$number = משמרת;
$regexp[$_] = shift foreach (0..$number-1);
$pattern = הצטרף '|', @regexp;

while ($line = <>) {
הדפס $line אם $line =~ /$pattern/;
}
^D

% multi_grep 2 shift עבור multi_grep
$number = משמרת;
$regexp[$_] = shift foreach (0..$number-1);

לפעמים זה יתרון לבנות דפוס מה קלט שצריך לנתח
והשתמש בערכים המותרים בצד שמאל של פעולות ההתאמה. בתור
דוגמה למצב הפרדוקסלי הזה, נניח שהקלט שלנו מכיל א
פועל פקודה שאמור להתאים לאחד מתוך קבוצה של פעלי פקודה זמינים, עם ה-
טוויסט נוסף שפקודות עשויות להיות מקוצרות כל עוד המחרוזת הנתונה היא ייחודית.
התוכנית להלן מדגימה את האלגוריתם הבסיסי.

% cat > keymatch
#!/usr/bin/perl
$kwds = 'העתק השוואת רשימה הדפסה';
while( $cmd = <> ){
$cmd =~ s/^\s+|\s+$//g; # חתוך חללים מובילים ונגררים
if( ( @matches = $kwds =~ /\b$cmd\w*/g ) == 1 ){
הדפס "command: '@matches'\n";
} elsif( @matches == 0 ){
הדפס "אין פקודה כזו: '$cmd'\n";
אחר} {
print "לא ייחודי: '$cmd' (יכול להיות אחד מ: @matches)\n";
}
}
^D

% התאמת מפתח
li
פקודה: 'רשימה'
co
לא ייחודי: 'co' (יכול להיות אחד מ: copy compare)
מדפסת
אין פקודה כזו: 'מדפסת'

במקום לנסות להתאים את הקלט למילות המפתח, אנו מתאימים את הסט המשולב של
מילות מפתח כנגד הקלט. פעולת התאמת הדפוס "$kwds =~ /\b($cmd\w*)/g" עושה
כמה דברים בו זמנית. הוא מוודא שהפקודה הנתונה מתחילה במקום שבו a
מילת המפתח מתחילה ("\b"). הוא סובל קיצורים עקב התוספת "\w*". זה אומר לנו את
מספר התאמות ("Scalar @matches") וכל מילות המפתח שהותאמו בפועל.
בקושי יכולת לבקש יותר.

הטבעה הערות ו משנים in a רגיל ביטוי
החל מסעיף זה, נדון בסט של פרל מוּרחָב דפוסי. אלה
הן הרחבות לתחביר הביטוי הרגולרי המסורתי המספקות חדש רב עוצמה
כלים להתאמת דפוסים. כבר ראינו הרחבות בצורת המינימלי
מבנים תואמים "??", "*?", "+?", "{n,m}?" ו-"{n,}?". רוב ההרחבות למטה
יש את הצורה "(?char...)", כאשר ה-"char" הוא תו שקובע את הסוג של
סיומת.

ההרחבה הראשונה היא הערה מוטבעת "(?#text)". זה מטמיע הערה ב-
ביטוי רגיל מבלי להשפיע על משמעותו. להערה אין סגירה כלשהי
סוגריים בטקסט. דוגמה היא

/(?# התאם מספר שלם:)[+-]?\d+/;

סגנון זה של הערות הוחלף במידה רבה על ידי ההערות הגולמיות והחופשיות
מותר עם השינוי "//x".

רוב השינויים, כגון "//i", "//m", "//s" ו-"//x" (או כל שילוב ביניהם) יכולים
יוטמע גם בביטוי רגולרי באמצעות "(?i)", "(?m)", "(?s)", ו-"(?x)". לדוגמה,

/(?i)yes/; # התאם את האותיות 'כן' ללא רגישות
/כן אני; # אותו דבר
/(?x)( # גרסה חופשית של ביטוי רגולרי של מספר שלם
[+-]? # התאם סימן אופציונלי
\d+ # תואם רצף של ספרות
)
/איקס;

לשינויים משובצים יכולים להיות שני יתרונות חשובים על פני השינויים הרגילים. מוטבע
משנים מאפשרים קבוצה מותאמת אישית של משנים כל אחד דפוס ביטוי רגיל. זה נהדר עבור
התאמת מערך של ביטויים רגולריים שחייבים להיות בעלי שינויים שונים:

$pattern[0] = '(?i)רופא';
$pattern[1] = 'ג'ונסון';
...
בעוד (<>) {
foreach $patt (@pattern) {
הדפס אם /$patt/;
}
}

היתרון השני הוא שמשנים מוטבעים (למעט "//p", שמשנה את כולו
regexp) משפיעים רק על ה-Regexp בתוך הקבוצה שבה השינוי המוטבע כלול. אז
ניתן להשתמש בקיבוץ כדי למקם את ההשפעות של השינוי:

/תשובה: ((?i)כן)/; # מתאים ל'תשובה: כן', 'תשובה: כן' וכו'.

מתקנים משובצים יכולים גם לכבות את כל המשתנים שכבר קיימים על ידי שימוש, למשל,
"(?-אני)". ניתן גם לשלב משנים לביטוי יחיד, למשל, "(?si)" מופעל
מצב קו בודד ומכבה חוסר רגישות לאותיות גדולות.

ניתן להוסיף גם מתקנים מוטבעים לקבוצה שאינה נלכדת. "(?im:regexp)" הוא א
קיבוץ ללא לכידה התואם ללא רגישות של אותיות רישיות "regexp" ומכבה ריבוי שורות
מצב.

הסתכלות קדימה ו הסתכלות מאחור
סעיף זה עוסק בקביעות של מבט קדימה והסתכלות מאחור. ראשית, קצת
רקע.

בביטויים רגולריים של Perl, רוב רכיבי ה-Regexp 'אוכלים' כמות מסוימת של מחרוזת כאשר
הם מתאימים. לדוגמה, האלמנט regexp "[abc}]" אוכל תו אחד מהמחרוזת
כאשר הוא תואם, במובן זה שפרל עובר למיקום התו הבא במחרוזת
אחרי המשחק. עם זאת, ישנם כמה אלמנטים שלא אוכלים דמויות (מקדימה
מיקום הדמות) אם הם תואמים. הדוגמאות שראינו עד כה הן העוגנים.
העוגן "^" מתאים לתחילת השורה, אבל לא אוכל שום תווים.
באופן דומה, המילה עוגן גבול "\b" תואמת בכל מקום שבו תו תואם "\w" נמצא
ליד דמות שלא, אבל היא לא אוכלת אף דמות בעצמה. עוגנים
הם דוגמאות ל רוחב אפס קביעות: רוחב אפס, מכיוון שהם אינם צורכים תווים, ו
קביעות, כי הן בודקות תכונה כלשהי של המחרוזת. בהקשר של ההליכה שלנו
האנלוגיה של היער להתאמת ביטויים רגועים, רוב רכיבי הביטוי הרגולרי מזיזים אותנו לאורך שביל, אבל
עוגנים מחייבים אותנו לעצור לרגע ולבדוק את הסביבה שלנו. אם הסביבה המקומית בודקת
החוצה, נוכל להמשיך קדימה. אבל אם הסביבה המקומית לא מספקת אותנו, אנחנו חייבים
לַחֲזוֹר עַל עִקבוֹתָיו.

בדיקת הסביבה כרוכה בהסתכלות קדימה על השביל, הסתכלות מאחור או
שניהם. "^" מסתכל מאחור, כדי לראות שאין תווים לפני כן. "$" מסתכל קדימה, ל
לראות שאין תווים אחרי. "\b" מסתכל הן קדימה והן מאחור, כדי לראות אם
הדמויות משני הצדדים נבדלות ב"המילה" שלהן.

קביעות המבט קדימה והמבט מאחור הן הכללות של מושג העוגן.
מבט קדימה ומבט מאחור הן קביעות ברוחב אפס המאפשרות לנו לציין אילו תווים אנחנו
רוצה לבדוק עבור. קביעת המבט קדימה מסומנת על ידי "(?=regexp)" והמבט מאחור
קביעה מסומנת על ידי "(?<=fixed-regexp)". חלק מהדוגמאות הן

$x = "אני תופס את חתול הבית 'טום-חתול' עם חתול חתול";
$x =~ /cat(?=\s)/; # מתאים ל'חתול' ב'חתול בית'
@catwords = ($x =~ /(?<=\s)cat\w+/g); # התאמות,
# $catwords[0] = 'תפוס'
# $catwords[1] = 'catnip'
$x =~ /\bcat\b/; # מתאים ל-'חתול' ב-'Tom-cat'
$x =~ /(?<=\s)cat(?=\s)/; # לא תואם; אין 'חתול' מבודד בפנים
# באמצע של $x

שימו לב שהסוגריים ב-"(?=regexp)" ו-"(?<=regexp)" אינם תופסים, שכן אלה
הן קביעות ברוחב אפס. לפיכך בביטוי הרגולרי השני, המחרוזות שנלכדו הן אלה
של כל הביטוי הרגולרי עצמו. מבט קדימה "(?=regexp)" יכול להתאים לביטויים רגועים שרירותיים, אבל
lookbehind "(?<=fixed-regexp)" פועל רק עבור ביטויים רגועים ברוחב קבוע, כלומר, מספר קבוע
של תווים באורך. לפיכך "(?<=(ab|bc))" זה בסדר, אבל "(?<=(ab)*)" לא. השלילה
גרסאות של קביעות ההסתכלות והמבט מאחור מסומנות ב-"(?!regexp)" ו-
"(? לֹא התאמה:

$x = "foobar";
$x =~ /foo(?!bar)/; # לא תואם, 'bar' עוקב אחרי 'foo'
$x =~ /foo(?!baz)/; # התאמות, 'baz' לא עוקב אחר 'foo'
$x =~ /(?

ה-"\C" אינו נתמך ב-lookbehind, מכיוון שההגדרה הבוגדנית ממילא של "\C"
יהפוך אפילו יותר כאשר הולכים אחורה.

הנה דוגמה שבה מחרוזת המכילה מילים מופרדות ריקות, מספרים ויחיד
מקפים יש לפצל למרכיביו. שימוש ב-"/\s+/" בלבד לא יעבוד, כי רווחים
אינם נדרשים בין מקפים, או מילה או מקף. מקומות נוספים לפיצול הם
הוקם על ידי הסתכלות קדימה ומאחור:

$str = "אחד שתיים - --6-8";
@toks = פיצול / \s+ # ריצת רווחים
| (?<=\S) (?=-) # כל שאינו רווח ואחריו '-'
| (?<=-) (?=\S) # א '-' ואחריו כל שאינו רווח
/x, $str; # @toks = qw(אחד שתיים - - - 6 - 8)

שימוש עצמאי ביטויי משנה ל למנוע מסלול חזרה
עצמאי ביטויי משנה הם ביטויים רגולריים, בהקשר של רגולרי גדול יותר
ביטוי, שמתפקדים ללא תלות בביטוי הרגולרי הגדול יותר. כלומר, הם
לצרוך כמה או מעט מהמחרוזת כרצונם מבלי להתחשב ביכולת של
הביטוי הרגולרי הגדול יותר כדי להתאים. ביטויי משנה בלתי תלויים מיוצגים על ידי "(?>regexp)".
אנו יכולים להמחיש את התנהגותם על ידי התחשבות תחילה בביטוי רגיל רגיל:

$x = "ab";
$x =~ /a*ab/; # התאמות

זה כמובן תואם, אבל בתהליך ההתאמה, תת-הביטוי "a*" תחילה
תפס את ה"א". עם זאת, פעולה זו לא תאפשר לכל הביטוי הרגולרי להתאים, אז לאחר מכן
בעקיבה לאחור, "a*" בסופו של דבר החזיר את ה-a והתאים למחרוזת הריקה. הנה, מה
"a*" תואם היה תלוי על מה שאר הביטוי הרגולרי תואם.

הפוך זאת עם תת-ביטוי עצמאי:

$x =~ /(?>a*)ab/; # לא תואם!

לביטוי המשנה הבלתי תלוי "(?>a*)" לא אכפת משאר הביטוי הרגולרי, אז הוא
רואה "א" ותופס אותה. אז שאר הביטוי הרגולרי "ab" לא יכול להתאים. כי
"(?>a*)" הוא עצמאי, אין חזרה לאחור ותת-הביטוי העצמאי כן
לא לוותר על ה"א" שלו. לכן ההתאמה של הביטוי הרגולרי בכללותו נכשלת. התנהגות דומה
מתרחש עם ביטויים רגולריים עצמאיים לחלוטין:

$x = "ab";
$x =~ /a*/g; # גפרורים, אוכל 'a'
$x =~ /\Gab/g; # לא תואם, אין 'a' זמין

כאן "//g" ו-"\G" יוצרים מסירת 'צוות תגים' של המחרוזת מביטוי רגולרי אחד ל-
אַחֵר. ביטויים רגועים עם תת-ביטוי עצמאי דומים מאוד לזה, עם מסירה של
המחרוזת לתת-הביטוי העצמאי, ומסירת המחרוזת חזרה ל-
מקיף ביטוי רגולרי.

היכולת של תת-ביטוי עצמאי למנוע חזרה לאחור יכולה להיות שימושית למדי.
נניח שאנו רוצים להתאים מחרוזת לא ריקה המוקפת בסוגריים עד לעומק של שתי רמות.
ואז הביטוי הרגולרי הבא מתאים:

$x = "abc(de(fg)h"; # סוגריים לא מאוזנים
$x =~ /\( ( [^()]+ | \([^()]*\) )+ \)/x;

הביטוי הרגולרי תואם סוגריים פתוחים, עותק אחד או יותר של חלופה וסגירה
מַאֲמָר מוּסְגָר. החלופה היא דו-כיוונית, כאשר החלופה הראשונה "[^()]+" תואמת את a
מחרוזת משנה ללא סוגריים והחלופה השנייה "\([^()]*\)" תואמת ל-a
מחרוזת משנה מופרדת בסוגריים. הבעיה עם הביטוי הרגולרי הזה היא שכן
פתולוגי: יש לו מכמים בלתי מוגדרים בצורת "(a+|b)+". דנו
בחלק 1, כיצד מכמים מקוננים כמו זה יכולים לקחת זמן רב באופן אקספוננציאלי
לבצע אם לא הייתה התאמה אפשרית. כדי למנוע את הפיצוץ האקספוננציאלי, אנחנו צריכים
למנוע חזרה חסרת תועלת בשלב מסוים. ניתן לעשות זאת על ידי סגירת החלק הפנימי
מכמת כתת-ביטוי עצמאי:

$x =~ /\( (?>[^()]+) | \([^()]*\) )+ \)/x;

כאן, "(?>[^()]+)" שובר את הניוון של חלוקה למחרוזות על ידי זולל כמה שיותר
את המיתר ככל האפשר ושמירה עליו. ואז כשלים בהתאמה נכשלים הרבה יותר מהר.

מותנה ביטויים
A מותנה ביטוי היא צורה של הצהרת אם-אז-אחר המאפשרת לבחור
אילו דפוסים יש להתאים, בהתבסס על תנאי כלשהו. ישנם שני סוגים של
ביטוי מותנה: "(?(תנאי) yes-regexp)" ו
"(?(תנאי) yes-regexp|no-regexp)". "(?(condition)yes-regexp)" הוא כמו 'if () {}'
הצהרה בפרל. אם ה"תנאי" נכון, ה-"yes-regexp" יתאים. אם ה
"תנאי" הוא שקר, ה-"yes-regexp" ידלג ופרל תעבור לשלב הבא
אלמנט regexp. הצורה השנייה היא כמו הצהרת 'if () {} else {}' בפרל. אם ה
"תנאי" נכון, ה-"yes-regexp" יתאים, אחרת ה-"no-regexp" יהיה
תואם.

ל"תנאי" יכולות להיות מספר צורות. הצורה הראשונה היא פשוט מספר שלם ב
סוגריים "(מספר שלם)". זה נכון אם ההפניה האחורית המתאימה "\integer" תואמת
מוקדם יותר בביטוי הרגולרי. ניתן לעשות את אותו הדבר עם שם המשויך ללכידה
קבוצה, נכתב כ"( )" או "('שם')". הצורה השנייה היא ברוחב אפס חשוף
קביעה "(?...)", או מבט קדימה, מבט לאחור או קביעת קוד (שנדונה ב
הסעיף הבא). קבוצת הטפסים השלישית מספקת מבחנים שמחזירים אמת אם
הביטוי מבוצע בתוך רקורסיה ("(R)") או שנקרא מתוך לכידה כלשהי
קבוצה, עם הפניה לפי מספר ("(R1)", "(R2)",...) או לפי שם ("(R&name)").

הצורה השלם או השם של ה"תנאי" מאפשרת לנו לבחור, ביתר גמישות,
מה להתאים על סמך מה שהתאים קודם לכן בביטוי הרגולרי. זה מחפש מילים של
טופס "$x$x" או "$x$y$y$x":

% simple_grep '^(\w+)(\w+)?(?(2)\g2\g1|\g1)$' /usr/dict/words
בריברי
קוקו
קוסקוס
מעשה
...
לִתְקוֹעַ
סך הכל
טוטו

ה"מצב" המבט מאחור מאפשר, יחד עם הפניות לאחור, חלק מוקדם יותר של ההתאמה
להשפיע על חלק מאוחר יותר של המשחק. לדוגמה,

/[ATGC]+(?(?<=AA)G|C)$/;

מתאים לרצף DNA כך שהוא מסתיים ב-"AAG", או בזוג בסיסים אחר
שילוב ו-"C". שימו לב שהצורה היא "(?(?(?<=AA)G|C)" ולא "(?((?<=AA))G|C)"; ל
קביעות ה-lookahead, lookbehind או קוד, הסוגריים סביב התנאי הם
לא נחוץ.

מגדיר בשם דפוסי
חלק מהביטויים הרגולריים משתמשים בתתי דפוסים זהים במספר מקומות. מתחיל עם פרל
5.10, אפשר להגדיר תתי-דפוסים בעלי שם בקטע של התבנית כך שהם
ניתן לקרוא בשם בכל מקום בתבנית. דפוס תחבירי זה עבור זה
קבוצת ההגדרה היא "(?(DEFINE)(? תבנית)...)". הכנסה של תבנית בעלת שם היא
נכתב בתור "(?&שם)".

הדוגמה להלן ממחישה תכונה זו באמצעות התבנית עבור מספרי נקודה צפה
שהוצג קודם לכן. שלושת תבניות המשנה שבהן נעשה שימוש יותר מפעם אחת הן ה
סימן אופציונלי, רצף הספרות עבור מספר שלם והשבר העשרוני. ה-DEFINE
הקבוצה בסוף התבנית מכילה את ההגדרה שלהם. שימו לב שהעשרוני
דפוס השבר הוא המקום הראשון שבו נוכל לעשות שימוש חוזר בתבנית המספרים השלמים.

/^ (?&osg)\ * ((?&int)(?&dec)? | (?&dec) )
(?: [eE](?&osg)(?&int) )?
$
(?(לְהַגדִיר)
(? [-+]?) # סימן אופציונלי
(? \d++) # מספר שלם
(? \.(?&int)) # שבר עשרוני
)/איקס

רקורסיבי דפוסי
תכונה זו (שהוצגה ב-Perl 5.10) מרחיבה משמעותית את הכוח של התבנית של Perl
תוֹאֵם. על ידי הפניה לקבוצת לכידה אחרת בכל מקום בדפוס עם ה
בנה "(?group-ref)", את דפוס בתוך הקבוצה המוזכרת משמש כ-an
תת-תבנית עצמאית במקום הפניה לקבוצה עצמה. בגלל הקבוצה
ניתן להכיל התייחסות בתוך לקבוצה שאליה היא מתייחסת, כעת ניתן להגיש בקשה
התאמת דפוסים למשימות שעד כה דרשו מנתח רקורסיבי.

כדי להמחיש תכונה זו, נעצב תבנית שתתאים אם מחרוזת מכילה א
פלינדרום. (זוהי מילה או משפט שתוך כדי התעלמות מרווחים, סימני פיסוק
ומקרה, קורא אותו אחורה כמו קדימה. אנו מתחילים בהתבוננות שהריק
מחרוזת או מחרוזת המכילה תו מילה אחד בלבד היא פלינדרום. אחרת זה חייב
יש תו מילה מלפנים וזהה בקצה שלה, עם עוד פלינדרום בפנים
בין.

/(?: (\w) (?...הנה פלינדרום...) \g{-1} | \w? )/x

הוספת "\W*" בשני קצוות כדי לבטל את מה שיש להתעלם ממנו, כבר יש לנו את המלא
תַבְנִית:

my $pp = qr/^(\W* (?: (\w) (?1) \g{-1} | \w? ) \W*)$/ix;
עבור $s ("saippuakauppias", "אדם, תוכנית, תעלה: פנמה!" ){
הדפס "'$s' הוא פלינדרום\n" אם $s =~ /$pp/;
}

ב-"(?...)" ניתן להשתמש בהפניות אחוריות מוחלטות ויחסיות כאחד. כל הדפוס יכול
יוכנס מחדש עם "(?R)" או "(?0)". אם אתה מעדיף לתת שם לקבוצות שלך, אתה יכול להשתמש
"(?&שם)" כדי להיכנס שוב לקבוצה זו.

A קצת of קֶסֶם: מבצע פרל קוד in a רגיל ביטוי
בדרך כלל, ביטויים רגועים הם חלק מביטויי Perl. קופונים הערכה ביטויים הופכים את זה
מסביב על ידי מתן אפשרות לקוד Perl שרירותי להיות חלק מ-Regexp. הערכת קוד
הביטוי מסומן "(?{קוד})", עם קוד שורה של הצהרות פרל.

שימו לב שתכונה זו נחשבת ניסיוני, ועשויה להשתנות ללא הודעה מוקדמת.

ביטויי קוד הם קביעות ברוחב אפס, והערך שהם מחזירים תלוי בהם
סביבה. ישנן שתי אפשרויות: או שביטוי הקוד משמש בתור a
מותנה בביטוי מותנה "(?(תנאי)...)", או שלא. אם הקוד
הביטוי הוא תנאי, הקוד מוערך והתוצאה (כלומר, התוצאה של ה-
המשפט האחרון) משמש כדי לקבוע אמת או שקר. אם ביטוי הקוד אינו
משמש כתנאי, הטענה תמיד מעריכה נכון והתוצאה מוכנסת ל-
משתנה מיוחד $^R. לאחר מכן ניתן להשתמש במשתנה $^R בביטויי קוד בהמשך
ביטוי רגולרי. הנה כמה דוגמאות מטופשות:

$x = "abcdef";
$x =~ /abc(?{print "היי אמא!";})def/; # התאמות,
# הדפסים 'היי אמא!'
$x =~ /aaa(?{print "היי אמא!";})def/; # לא תואם,
# לא 'היי אמא!'

שימו לב היטב לדוגמא הבאה:

$x =~ /abc(?{print "היי אמא!";})ddd/; # לא תואם,
# לא 'היי אמא!'
# אבל למה לא?

במבט ראשון, הייתם חושבים שזה לא צריך להדפיס, כי ברור שה"ddd" לא
הולך להתאים למחרוזת היעד. אבל תסתכל על הדוגמה הזו:

$x =~ /abc(?{print "היי אמא!";})[dD]dd/; # לא תואם,
# אבל _האם_ מדפיס

הממ. מה קרה פה? אם עקבת אחריך, אתה יודע שהדפוס שלמעלה
צריך להיות למעשה (כמעט) זהה לזה האחרון; תוחם את ה"ד" בתו
הכיתה לא תשנה את מה שהיא מתאימה. אז למה הראשון לא מדפיס בזמן שה
השני עושה?

התשובה טמונה באופטימיזציות שמנוע הרקס מבצע. במקרה הראשון, כל
מנוע רואה הם דמויות ישנות רגילות (מלבד המבנה "?{}"). זה מספיק חכם
להבין שהמחרוזת 'ddd' לא מופיעה במחרוזת היעד שלנו לפני כן
להפעיל את התבנית. אבל במקרה השני, הטעינו אותו לחשוב כך
הדפוס שלנו מסובך יותר. זה מסתכל, רואה את כיתת הדמות שלנו ומחליט
שהוא יצטרך להריץ את התבנית בפועל כדי לקבוע אם היא תואמת או לא, וכן
בתהליך ההפעלה הוא פוגע במשפט ההדפסה לפני שהוא מגלה שאנחנו לא
יש התאמה.

כדי להסתכל מקרוב על האופן שבו המנוע מבצע אופטימיזציות, עיין בסעיף "פרגמות ו
איתור באגים" למטה.

יותר כיף עם "?{}":

$x =~ /(?{print "היי אמא!";})/; # התאמות,
# הדפסים 'היי אמא!'
$x =~ /(?{$c = 1;})(?{print "$c";})/; # התאמות,
# הדפסים '1'
$x =~ /(?{$c = 1;})(?{print "$^R";})/; # התאמות,
# הדפסים '1'

מעט הקסם שהוזכר בכותרת המדור מתרחש כאשר הביטוי הרגולרי חוזר ב-
תהליך חיפוש התאמה. אם הביטוי הרגולרי חוזר על ביטוי קוד ואם
המשתנים המשמשים בתוך הם מקומיים באמצעות "מקומי", השינויים במשתנים
המיוצר על ידי ביטוי הקוד בוטלו! לפיכך, אם נרצה לספור כמה פעמים א
דמות הותאמה בתוך קבוצה, נוכל להשתמש, למשל,

$x = "aaaa";
$count = 0; # אתחול ספירת 'a'
$c = "בוב"; # בדוק אם $c מתקלקל
$x =~ /(?{local $c = 0;}) # אתחול ספירת
( תואם # 'א'
(?{local $c = $c + 1;}) ספירת # תוספת
)* # עשה זאת בכל מספר פעמים,
aa # אבל התאם את 'aa' בסוף
(?{$count = $c;}) # העתק מקומי $c var לתוך $count
/איקס;
print "ספירת 'a' היא $count, המשתנה \$c הוא '$c'\n";

זה מודפס

ספירת 'a' היא 2, המשתנה $c הוא 'bob'

אם נחליף את " (?{local $c = $c + 1;})" ב-" (?{$c = $c + 1;})", המשתנה
שינויים הם לֹא בוטלה במהלך החזרה לאחור, ואנחנו מקבלים

ספירת 'a' היא 4, המשתנה $c הוא 'bob'

שים לב שרק שינויים במשתנה מקומי בוטלו. תופעות לוואי אחרות של קוד
ביצוע ביטוי הם קבועים. לכן

$x = "aaaa";
$x =~ /(a(?{print "Yow\n";}))*aa/;

ייצור

יואו
יואו
יואו
יואו

התוצאה $^R ממוקמת אוטומטית, כך שהיא תתנהג כראוי בנוכחות
של החזרה לאחור.

דוגמה זו משתמשת בביטוי קוד בתנאי כדי להתאים למאמר מוגדר
'the' באנגלית או 'der|die|das' בגרמנית:

$lang = 'DE'; # השתמש בגרמנית
...
$text = "das";
הדפס "מותאם\n"
if $text =~ /(?(?{
$lang eq 'EN'; # האם השפה היא אנגלית?
})
את | # אם כן, התאם את 'ה'
(der|die|das) # else, match 'der|die|das'
)
/xi;

שימו לב שהתחביר כאן הוא "(?(?{...})yes-regexp|no-regexp)", לא
"(?((?{...}))yes-regexp|no-regexp)". במילים אחרות, במקרה של ביטוי קוד, אנחנו
לא צריך את הסוגריים הנוספים מסביב לתנאי.

אם תנסה להשתמש בביטויי קוד שבהם טקסט הקוד כלול בתוך אינטרפולציה
משתנה, במקום להופיע פשוטו כמשמעו בדפוס, פרל עשוי להפתיע אותך:

$bar = 5;
$pat = '(?{ 1 })';
/foo(?{ $bar })bar/; # קומפילציה בסדר, $bar לא מתערב
/foo(?{ 1 })$bar/; # קומפילציה בסדר, אינטרפולציה של $bar
/foo${pat}bar/; # שגיאת קומפילציה!

$pat = qr/(?{ $foo = 1 })/; # קדם קומפילציה של קוד regexp
/foo${pat}bar/; # קומפילציה בסדר

אם ל-Regexp יש משתנה המשלב ביטוי קוד, Perl מתייחס ל-Regxp כאל
שגיאה. עם זאת, אם ביטוי הקוד מורכב מראש למשתנה, אינטרפולציה כן
בסדר. השאלה היא למה זו טעות?

הסיבה היא שאינטרפולציה משתנים וביטויי קוד מהווים יחד אבטחה
לְהִסְתָכֵּן. השילוב מסוכן כי מתכנתים רבים שכותבים מנועי חיפוש
לעתים קרובות לוקחים קלט של המשתמש ומחברים אותו ישירות לביטוי רגולי:

$regexp = <>; # קרא את הביטוי הרגולרי שסופק על ידי המשתמש
$chomp $regexp; # היפטר משורה חדשה אפשרית
$text =~ /$regexp/; # חפש ב-$text עבור ה-$regexp

אם המשתנה $regexp מכיל ביטוי קוד, המשתמש יוכל להפעיל באופן שרירותי
קוד פרל. לדוגמה, ג'וקר כלשהו יכול לחפש "system('rm -rf *');" למחוק את שלך
קבצים. במובן זה, השילוב של אינטרפולציה וביטויי קוד כתמים שֶׁלְךָ
ביטוי רגולרי. אז כברירת מחדל, שימוש גם באינטרפולציה וגם בביטויי קוד באותו ביטוי רגולרי
זה אסור. אם אינך מודאג ממשתמשים זדוניים, אפשר לעקוף
בדיקת אבטחה זו על ידי הפעלת "use re 'eval'":

השתמש מחדש ב'eval'; # לזרוק זהירות מהדלת
$bar = 5;
$pat = '(?{ 1 })';
/foo${pat}bar/; # קומפילציה בסדר

צורה נוספת של ביטוי קוד היא ה דפוס קוד ביטוי. קוד הדפוס
ביטוי הוא כמו ביטוי קוד רגיל, אלא שהתוצאה של הקוד
הערכה מטופלת כביטוי רגולרי ומתאימה באופן מיידי. דוגמה פשוטה
is

$length = 5;
$char = 'a';
$x = 'aaaaabb';
$x =~ /(??{$char x $length})/x; # התאמות, יש 5 מתוך 'a'

דוגמה אחרונה זו מכילה גם ביטויי קוד רגילים וגם ביטויי קוד. זה מזהה
האם למחרוזת בינארית 1101010010001... יש מרווח פיבונאצי 0,1,1,2,3,5,... מתוך
שנות ה-1:

$x = "1101010010001000001";
$z0 = ''; $z1 = '0'; # תנאים התחלתיים
הדפס "זהו רצף פיבונאצי\n"
אם $x =~ /^1 # תואם ל-'1' הראשוני
(?:
((??{ $z0 })) # תואם לאיזה '0'
1 # ולאחר מכן '1'
(?{ $z0 = $z1; $z1 .= $^N; })
)+ # חזור לפי הצורך
$ # זה כל מה שיש
/איקס;
printf "הרצף הגדול ביותר שהתאים היה %d\n", length($z1)-length($z0);

זכור ש-$^N מוגדר לכל מה שהתאים לקבוצת הלכידה האחרונה שהושלמה. זֶה
הדפסים

זה רצף של פיבונאצ'י
הרצף הגדול ביותר שהתאים היה 5

הא! נסה את זה עם חבילת regexp של מגוון הגינה שלך...

שימו לב שהמשתנים $z0 ו-$z1 אינם מוחלפים כאשר ה-Regexp מורכב, כמו
קורה עבור משתנים רגילים מחוץ לביטוי קוד. במקום זאת, כל בלוק הקוד הוא
מנותח כקוד perl בו-זמנית ש-perl מרכיב את הקוד המכיל את ה-literal
דפוס ביטוי רגיל.

הביטוי הרגולרי ללא השינוי "//x" הוא

/^1(?:((??{ $z0 }))1(?{ $z0 = $z1; $z1 .= $^N; }))+$/

מה שמראה שעדיין אפשריים רווחים בחלקי הקוד. בכל זאת, בזמן העבודה
עם קוד וביטויים מותנים, הצורה המורחבת של ביטויים רגועים כמעט נחוצה ב
יצירה וניפוי באגים של ביטויים מחודשים.

חזרה לאחור לִשְׁלוֹט פעלים
Perl 5.10 הציג מספר פעלי שליטה שנועדו לספק שליטה מפורטת עליהם
תהליך החזרה לאחור, על ידי השפעה ישירה על מנוע ה- regexp ועל ידי אספקה
טכניקות ניטור. מכיוון שכל התכונות בקבוצה זו הן ניסיוניות וכפופות
שינוי או הסרה בגרסה עתידית של Perl, הקורא המתעניין מופנה
"פעלי בקרת מסלולים מיוחדים" ב-perlre לתיאור מפורט.

להלן רק דוגמה אחת, הממחישה את פועל השליטה "(*FAIL)", שיכול להיות
קיצור של "(*F)". אם זה מוכנס ל-Regexp זה יגרום לו להיכשל, בדיוק כמו
זה יהיה באי התאמה כלשהי בין התבנית למיתר. עיבוד של הביטוי הרגולרי
ממשיך כפי שהיה לאחר כל כשל "רגיל", כך, למשל, המיקום הבא
במחרוזת או אלטרנטיבה אחרת תנוסה. כמו אי התאמה לא משמרת
לכידת קבוצות או להפיק תוצאות, ייתכן שיהיה צורך להשתמש בזה בשילוב עם
קוד מוטבע.

%count = ();
"supercalifragilisticexpialidocious" =~
/([aeiou])(?{ $count{$1}++; })(*FAIL)/i;
printf "%3d '%s'\n", $count{$_}, $_ for (מקשי מיון %count);

התבנית מתחילה במחלקה המתאימה לקבוצת משנה של אותיות. בכל פעם שזה מתאים, א
הצהרה כמו "$count{'a'}++;" מבוצע, ומגדיל את מונה המכתב. לאחר מכן
"(*FAIL)" עושה מה שהוא אומר, ומנוע ה-Regexp ממשיך לפי הספר: כל עוד
מכיוון שלא הגיע לקצה המחרוזת, המיקום מתקדם לפני שמחפשים אותו
תנועה נוספת. לפיכך, התאמה או אי התאמה אינה משנה, ומנוע הביטוי הרגולרי ממשיך
עד שהמחרוזת כולה נבדקה. (זה מדהים שפתרון חלופי
שימוש במשהו כמו

$count{lc($_)}++ עבור split('', "supercalifragilisticexpialidocious");
printf "%3d '%s'\n", $count2{$_}, $_ for ( qw{ aeiou } );

הוא איטי במידה ניכרת.)

פרגמות ו ניפוי
אם כבר מדברים על ניפוי באגים, ישנן מספר פרגמות זמינות לשליטה וניפוי באגים בביטויים מחודשים
פרל. כבר נתקלנו בפרגמה אחת בסעיף הקודם, "use re 'eval';",
המאפשר אינטרפולציה משתנים וביטויי קוד להתקיים במקביל ב-Regexp. האחר
פרגמות הן

השתמש ב-re 'taint';
$tainted = <>;
@parts = ($tainted =~ /(\w+)\s+(\w+)/; # @parts עכשיו נגוע

פרגמת "הכתם" גורמת לכל תת-מחרוזות מהתאמה עם משתנה נגוע
נגוע גם כן. זה לא המקרה בדרך כלל, מכיוון ש-Regexs משמשים לעתים קרובות כדי לחלץ את
ביטים בטוחים ממשתנה נגוע. השתמש ב"כתם" כאשר אתה לא מחלץ סיביות בטוחות, אבל
מבצעים עיבוד אחר. גם פרגמות "כתם" וגם "אבאליות" הן מבחינה מילונית
scoped, כלומר הם בתוקף רק עד סוף הבלוק המקיף את
פרגמות.

השתמש ב-re '/m'; # או כל דגל אחר
$multiline_string =~ /^foo/; # /m משתמע

הפרגמה "re '/flags'" (שהוצגה בפרל 5.14) מפעילה את הביטוי הרגולרי הנתון
דגלים עד סוף ההיקף המילוני. ראה "מצב '/flags'" ב-re לפרטים נוספים.

השתמש מחדש ב-'debug';
/^(.*)$/s; # פלט מידע ניפוי באגים

השתמש מחדש ב-'debugcolor';
/^(.*)$/s; # פלט מידע ניפוי באגים בצבע חי

הפרגמות הגלובליות "debug" ו-"debugcolor" מאפשרות לקבל מידע מפורט על ניפוי באגים
הידור וביצוע של ביטוי regexp. "debugcolor" זהה ל-debug, מלבד איתור הבאגים
המידע מוצג בצבע על מסופים שיכולים להציג רצפי צבע של termcap.
הנה פלט לדוגמה:

% perl -e 'השתמש מחדש ב"ניפוי באגים"; "abc" =~ /a*b+c/;'
קומפילציה של REx 'a*b+c'
מידה 9 תחילה ב-1
1: כוכב(4)
2: מדוייק (0)
4: PLUS(7)
5: מדוייק (0)
7: בדיוק (9)
9: הסוף(0)
צף 'bc' ב-0..2147483647 (בודק צף) minlen 2
מנחש את תחילת המשחק, REx 'a*b+c' נגד 'abc'...
נמצא substr 'bc' צף בהיסט 1...
ניחוש: התאמה בהיסט 0
התאמת REx 'a*b+c' מול 'abc'
הגדרת היקף EVAL, savestack=3
0 <> | 1: כוכב
EXACT יכול להתאים 1 פעמים מתוך 32767...
הגדרת היקף EVAL, savestack=3
1 | 4: פלוס
EXACT יכול להתאים 1 פעמים מתוך 32767...
הגדרת היקף EVAL, savestack=3
2 | 7: בדיוק
3 <> | 9: סוף
התאמה מוצלחת!
משחרר Rex: 'a*b+c'

אם הגעת כל כך רחוק לתוך המדריך, אתה כנראה יכול לנחש מה ההבדל
חלקים מפלט ניפוי הבאגים אומרים לך. החלק הראשון

קומפילציה של REx 'a*b+c'
מידה 9 תחילה ב-1
1: כוכב(4)
2: מדוייק (0)
4: PLUS(7)
5: מדוייק (0)
7: בדיוק (9)
9: הסוף(0)

מתאר את שלב ההידור. כוכב(4) פירושו שיש אובייקט מסומן בכוכב, בזה
מקרה 'a', ואם הוא תואם, עבור לשורה 4, כלומר, PLUS(7). השורות האמצעיות מתארות חלק
היוריסטיות ואופטימיזציות שבוצעו לפני התאמה:

צף 'bc' ב-0..2147483647 (בודק צף) minlen 2
מנחש את תחילת המשחק, REx 'a*b+c' נגד 'abc'...
נמצא substr 'bc' צף בהיסט 1...
ניחוש: התאמה בהיסט 0

לאחר מכן ההתאמה מתבצעת והשורות הנותרות מתארות את התהליך:

התאמת REx 'a*b+c' מול 'abc'
הגדרת היקף EVAL, savestack=3
0 <> | 1: כוכב
EXACT יכול להתאים 1 פעמים מתוך 32767...
הגדרת היקף EVAL, savestack=3
1 | 4: פלוס
EXACT יכול להתאים 1 פעמים מתוך 32767...
הגדרת היקף EVAL, savestack=3
2 | 7: בדיוק
3 <> | 9: סוף
התאמה מוצלחת!
משחרר Rex: 'a*b+c'

כל שלב הוא בצורת "n ", עם " "החלק של המחרוזת תואם ו" "
החלק שעדיין לא תואם. ה-"| 1: STAR" אומר שפרל נמצאת בשורה מספר 1 ב-
רשימת אוסף למעלה. ראה "ניפוי באגים בביטויים רגילים" ב-perldebguts למידע נוסף
פרט.

שיטה חלופית לאיתור באגים של ביטויים רגועים היא הטמעת הצהרות "הדפסה" בתוך
ביטוי רגולרי. זה מספק תיאור מכה אחר מכה של החזרה לאחור בסירוגין:

"שזה" =~ m@(?{print "התחל בעמדה ", pos, "\n";})
t(?{הדפס "t1\n";})
h(?{הדפס "h1\n";})
i(?{הדפס "i1\n";})
s(?{הדפס "s1\n";})
|
t(?{הדפס "t2\n";})
h(?{הדפס "h2\n";})
a(?{הדפס "a2\n";})
t(?{הדפס "t2\n";})
(?{הדפס "בוצע בעמדה ", pos, "\n";})
@איקס;

הדפסים

התחל בעמדה 0
t1
h1
t2
h2
a2
t2
נעשה בעמדה 4

השתמש ב-perlretut באינטרנט באמצעות שירותי onworks.net


שרתים ותחנות עבודה בחינם

הורד אפליקציות Windows & Linux

פקודות לינוקס

Ad




×
פרסומת
❤️קנו, הזמינו או קנו כאן - ללא עלות, עוזר לשמור על שירותים בחינם.