ה Regexp הלא נכון

28/07/2023

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

^\s*(.*)\s*$

אני יכול לראות למה זה נראה כמו רעיון טוב - אתה חושב שאתה תופס את הטקסט שבאמצע, ויותר מזה אם ננסה את הביטוי ונדפיס את ה Capture Group הראשון התוצאה "תיראה" נכונה:

$ echo "     hello world    " | perl -nE '/^\s*(.*)\s*$/ && say $1'
hello world

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

$ echo "     hello world    " | perl -nE '/^\s*(.*)\s*$/ && say "[$1]"' 
[hello world    ]

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

$ echo "     hello world    " | perl -nE '/^\s*(.*?)\s*$/ && say "[$1]"'
[hello world]

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