חד־שורתיים מבוססי regex#
הפרק הקודם שמר את ה־regexps ברמה שמשתמשי sed או awk כבר מכירים: תבניות ליטרליות בתוך m// ו־s///. פרק זה מכסה חד־שורתיים שצורתם תלויה בתכונת regex מעבר להתאמה פשוטה - חילוצים, לכידות, lookarounds, קוד־בהחלפה, ושכתובים לא־הרסניים.
קוראים המכירים כבר את המבנים ((?:...), (?<name>...), (?=...), המתאמים /e ו־/r) יכולים לדפדף לקבלת המסגרת של שורת הפקודה. קוראים היודעים מה /g עושה אך מעולם לא כתבו /e יפיקו את המרב מקריאה רצופה.
לשפת ה־regex עצמה, ראו את מדריך הביטויים הרגולריים.
חילוץ כל ההתאמות#
/g בהקשר רשימה מחזיר כל התאמה, לא רק את הראשונה.
# Every integer in the input
pperl -ne 'print "$_\n" for /-?\d+/g' file.txt
# Every IPv4-shaped substring
pperl -lne 'print for /\b(?:\d{1,3}\.){3}\d{1,3}\b/g' access.log
# Every HTTP header value (naive: no folded headers)
pperl -nE 'say $1 if /^[\w-]+:\s*(.+)$/' headers.txt
say (מופעל על־ידי -E) מוסיף שורה חדשה, חוסך "\n" אחד ושומר על תוכנית קצרה.
מכמתים לא־חמדניים#
*?, +?, ??, {n,m}? - להתאים כמה שפחות תווים.
# Everything between the first < and the next > (tag-by-tag)
pperl -lne 'print for /<(.+?)>/g' markup.html
# Every quoted string (double quotes, no escape handling)
pperl -lne 'print for /"([^"]*)"/g' config.txt
מחלקת התווים השלילית [^"]* היא בדרך כלל לא־חמדנית מהירה ובטוחה יותר מאשר .*? כשאתם יודעים מה אסור שיופיע בפנים.
לכידות בהחלפה#
הצד הימני של s/// יכול להפנות ללכידות בצד השמאלי.
# Swap every "word1 word2" pair
pperl -pe 's/(\w+)\s+(\w+)/$2 $1/g' file.txt
# Quote every unquoted key in key=value pairs
pperl -pe 's/(\w+)=/$1="/g; s/=([^"\n]+)/"$1"/g' config.txt
# Increase every trailing number by one
pperl -pe 's/(\d+)$/$1 + 1/e' file.txt
/e - ההחלפה היא קוד Perl#
המתאם /e מתייחס להחלפה כקוד; ערך החזרה שלו הוא מה שמוחלף.
# Number every word in the file (global counter)
pperl -pe 's/(\w+)/++$i . ".$1"/ge' file.txt
# Number words per line (counter reset each line)
pperl -pe '$i = 0; s/(\w+)/++$i . ".$1"/ge' file.txt
# Wrap every integer in base 16
pperl -pe 's/\d+/sprintf "0x%x", $&/ge' file.txt
# Convert Celsius-labelled numbers to Fahrenheit
pperl -pe 's/(\d+)C\b/sprintf "%.1fF", $1 * 9 / 5 + 32/ge' weather.txt
/ge ביחד: להעריך את הצד הימני כקוד, לעשות זאת לכל התאמה. $& הוא כל הטקסט שהותאם; $1, $2, … הן לכידות.
/ee מעריך פעמיים - ה־e הראשון מייצר מחרוזת, השני מעריך את אותה מחרוזת. שימושי כשמחרוזת ההחלפה היא בעצמה קוד דינמי שנקרא מקלט; נדרש לעיתים נדירות, סכנה לעיתים קרובות.
/r - החלפה לא־הרסנית#
/r מחזיר את המחרוזת המשונה במקום לשכתב את $_. המקור נשאר ללא שינוי.
# Print filename and its .bak variant side by side
ls *.txt | pperl -pe '$_ = $_ . ($_ =~ s/$/.bak/r)'
# Compute a transformed version without touching $_
pperl -ne 'my $upper = $_ =~ tr/a-z/A-Z/r; print $_, $upper' file.txt
פנו ל־/r כששורה יחידה צריכה להיות מודפסת בשתי צורות, או כשהטרנספורמציה מותנית ואתם רוצים את השורה ללא שינוי חזרה בענף הכישלון.
לכידות בעלות שם#
(?<name>...) לוכד לתוך $+{name} ולתוך %+.
# Parse combined-log-format access lines
pperl -nE '
if (/^(?<ip>\S+).*?"(?<method>\S+) (?<path>\S+)/) {
say "$+{ip} $+{method} $+{path}";
}
' access.log
לכידות בעלות שם משתלמות ברגע שלתבנית יש יותר משתי קבוצות, או כשאותה קבוצה צריכה להיות מופנת גם בתבנית וגם בקוד ההחלפה.
lookahead ו־lookbehind#
היגדים ברוחב אפס: התאמת מיקום שבו הטקסט מסביב מקיים תנאי, ללא צריכת התנאי עצמו.
# Digits preceded by $ (e.g. "$42" → 42, ignore "42")
pperl -lne 'print for /(?<=\$)\d+/g' prices.txt
# Words NOT followed by "!"
pperl -lne 'print for /\b\w+\b(?!!)/g' shouts.txt
# Insert CRLF only where LF is not already preceded by CR
pperl -pe 's/(?<!\r)\n/\r\n/g' unix.txt
צמדים נפוצים:
Lookaround | משמעות |
|---|---|
| התווים הבאים מתאימים ל־ |
| התווים הבאים אינם מתאימים ל־ |
| התווים הקודמים מתאימים ל־ |
| התווים הקודמים אינם מתאימים ל־ |
lookbehind ב־pperl תומך בתבניות באורך משתנה; ראו ביטויים רגולריים: עוגנים והיגדים.
התאמות רב־שורתיות על פני קלט slurped#
-0777 עושה slurp לכל הקובץ לתוך $_. המתאמי regex שחשובים במצב זה:
/s-.מתאים ל־\n./m-^ו־$מתאימים בכל התחלה/סוף שורה, לא רק בהתחלה/סוף של כל המחרוזת.
# Every BEGIN...END block (non-greedy), each on one output line
pperl -0777 -lne '
while (/BEGIN(.*?)END/sg) {
(my $body = $1) =~ s/\n/ /g;
print $body;
}
' text.txt
# Paragraphs where every line starts with ">"
pperl -00 -ne 'print if /\A(?:>.*\n?)+\z/m' mail.txt
\A ו־\z מעגנים את התחלת וסוף כל המחרוזת, בלתי־מושפעים מ־/m. השתמשו בהם כש־/m דלוק אבל אתם באמת מתכוונים לכל המחרוזת.
תעתוק עם tr#
tr (נכתב גם y) היא החלפה תו־אחר־תו. לא regex, אבל שכן קרוב - והכלי הנכון לעבודות עם מערכי תווים.
pperl -pe 'tr/A-Za-z/N-ZA-Mn-za-m/' # ROT13
pperl -pe 'tr/A-Za-z/a-zA-Z/' # swap case
pperl -pe 'tr/a-z//d' # delete lowercase letters
pperl -pe 'tr/ \t/ /s' # squeeze whitespace runs to one space
# Count commas on each line (tr returns the count)
pperl -ne 'print tr/,//, "\n"' data.csv
הדגל d מוחק תווים בקבוצה השמאלית שאין להם מקבילה בימנית. הדגל s מרסק רצפים. הדגל c משלים את הקבוצה השמאלית (כל מה שלא מופיע ברשימה).
ניתוח תת־מחרוזות מופרדות#
CSV עם פסיקים מצוטטים#
פיצול מהיר־ומלוכלך המכבד שדות במרכאות כפולות:
pperl -ne '
my @F = /"([^"]*)"|([^,]+)/g;
@F = grep defined, @F;
print join("|", @F), "\n";
' quoted.csv
נכון ומהיר מספיק לחד־פעמי. לכל דבר שחייב לטפל במרכאות מוטמעות ("he said ""hi"""), השתמשו ב־Text::CSV; ראו numeric.
מחרוזות שאילתת URL#
# Each key=value pair on its own line
pperl -lne 'print for /([^?&=]+)=([^&]*)/g' urls.txt
חד־שורתיי חילוץ מעשיים#
מילים לפי אורך#
# Words of exactly 5 characters
pperl -lne 'print for /\b\w{5}\b/g' file.txt
מספרים עם יחידות#
pperl -lne 'print for /\b\d+(?:\.\d+)?\s*(?:ms|s|kb|mb|gb)\b/gi' timings.txt
HTTP User-Agent מ־log בקשות#
pperl -nE 'say $1 if /^User-Agent: (.+)$/' request.log
סוגריים מסולסלים מאוזנים (עד כמה שמנוע ה־regex של pperl תומך)#
מנוע ה־regex של pperl תומך ברקורסיה דרך (?R) ו־(?1), ולכן איזון סוגריים ברמה יחידה הוא חד־שורתי:
pperl -0777 -nE 'say $& while /\{(?:[^{}]|(?R))*\}/g' code.txt
למבנים מקוננים עמוקות, פנו לפרסר. Regex הוא הכלי הנכון עד למורכבות שבה הוא מפסיק להיות כזה.
לקריאה נוספת#
מדריך הביטויים הרגולריים - השפה תחת כל מתכון כאן, כולל מתאמים, ביצועים, ו־Unicode.
m- אופרטור ההתאמה.s- החלפה, המערך המלא של המתאמים.tr- מדריך עיון לתעתוק.progression - מתכוני
s///פשוטים יותר ללא לכידות או קוד.perlop- הצורהqr//להידור מוקדם של תבניות המופנות בשם בתוך חד־שורתי.