מי לא מכיר ביטויים רגולריים? אולי אחד הכלים הידועים לשמצה בג'אווהסקריפט ובכלל. אבל אם מגבילים אותו לניתוח טקסט, ביטויים רגולריים הם כלי חשוב מאוד בארגז הכלים של כל מתכנת, גם של מתכנתי צד לקוח ומתכנתי ג'אווהסקריפט. למי שלא יודע/ לא זוכר – אני משתמש בביטויים רגולריים כדי לבצע פעולות שונות על טקסט. למשל על מנת לבדוק אם מחרוזת מסוימת עונה למה שאני מגדיר. למשל, אם אני רוצה לוודא שטקסט מסוים מכיל אך ורק אותיות ולא מספרים, אני אעשה משהו כזה:
let text = 'someUserName';
/^[A-Za-z]*$/.test(text);// true
text = "' or 68 = '66; DROP ALL TABLES; --';";
/^[A-Za-z]*$/.test(text);// false
בדוגמה לעיל למשל, אני משתמש במתודה test, שנמצאת בפרוטוטייפ של ביטוי רגולרי – כלומר כל ביטוי רגולרי בג'אווהסקריפט מכיל אותה. היא מקבלת משתנה ובודקת אם הביטוי הרגולרי נכון. במידה וכן, מקבלים true, במידה ולא – מקבלים false. כאן למשל, אני בודק אם מחרוזת מסוימת מכילה רק A-Z או a-z. במידה ואני מקבל מחרוזת טקסט שעומדת בקריטריונים האלו – אני מקבל true. במידה ולא, כמו למשל מישהו שמנסה לעשות לי SQL injection, אני אחזיר false.
לכל ביטוי רגולרי יש גם פלאגים.
פלאגים משמשים לשינוי ההתנהגות של הביטוי הרגולרי עצמו. למשל, בדוגמה יש ביטוי רגולרי שכולל גם את A-Z וגם את a-z – כדי לכלול את כל האותיות הגדולות והקטנות (ואותן בכלל). אם אני אשתמש בפלאג i, אני יכול לומר שאם אני משתמש ב-a-z אז זה כמו להשתמש ב-A-Z וההיפך. כלומר לא אכפת לי מאותיות גדולות או קטנות.
let text = 'someUserName';
/^[A-Z]*$/i.test(text);// true
text = "someUserName";
/^[A-Z]*$/.test(text);// false
בביטוי הראשון, אני משתמש בפלאג i. ככה שהביטוי הרגולרי A-Z תופס גם אותיות גדולות וגם קטנות והוא יעביר לי את המחרוזת userName (שיש בה גם אותיות קטנות ואות גדולה אחת). בביטוי השני אני לא משתמש בו – שימו לב שאין סלאש i שם. ואז אותה מחרוזת תיכשל – כי הביטוי אומר בעצם שהוא מוכן לקבל רק אותיות גדולות A-Z.
יש לנו כמה פלאגים שימושיים – למשל m שהוא רלוונטי לטקסט מרובה שורות. כשאנחנו מדברים על טקסט מרובה שורות – כלומר יש בו את התו n\, אנחנו נכנסים לעולם אחר של כאב. אחד הבאגים היותר ידועים של ג'אווהסקריפט היתה שהתו . בביטוי רגולרי, שאומר בעצם 'כל תו' – לא תופס ירידת שורה. אני אדגים באמצעות הביטוי הרגולרי
/^.$/
שאומר בעצם תו אחד בלבד, לא משנה מאיזה סוג. הוא אמור לתפוס כל תו שהוא: אות באנגלית, אות בעברית או בערבית. מתי הוא ייכשל? רק במחרוזת ריקה:
let text = 'a';
/^.$/.test(text);// true
text = 'ג';
/^.$/.test(text);// true
text = 'ض';
/^.$/.test(text);// true
text = '';
/^.$/.test(text);// false
text = 'cd';
/^.$/.test(text);// false
קל לראות שכל עוד אני מספק אות אחת (ואות אחד בלבד!), הביטוי יעבור. סיפקתי מחרוזת ריקה? יותר מתו אחד? בום. מקבל false.
מה הבעיה? הבעיה מתחילה אם אני בודק ירידת שורה. מה עם ירידת שורה? היא נחשבת כאות? ההגיון אומר שכן, אבל אם אני בודק את זה אז:
text = '\n';
/^.$/.test(text);// false
היו כל מיני טריקים ושטיקים לעקוף את זה וחבל. ב-ES2018 הוסיפו פשוט פלאג s שאומר שהנקודה היא רלוונטית גם לירידת שורה. כלומר:
text = '\n';
/^.$/s.test(text) // true
שימו לב ל /s. אז מעכשיו – אם אתם כותבים ביטויים רגולריים, תדעו להכניס את s אם יש לכם נקודה (כל תו) בביטוי רגולרי ואתם רוצים לתפוס ירידת שורה. ואם אתם לא כותב כותבים ביטויים רגולריים? אז למדתם משהו חדש 🙂
2 תגובות
היי, תודה על המאמר.
אבל במה זה שונה מפלאג m של מולטי ליין?
יש תחושה שהשדרוגים של js הפכו להיות מינוריים. זה כבר דברים מאוד קטנים.