ES2018 – פלאג חדש לביטויים רגולריים

פלאג חדש ומתבקש לביטוי רגולרי מגיע סוף סוף לג'אווהסקריפט

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


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 אם יש לכם נקודה (כל תו) בביטוי רגולרי ואתם רוצים לתפוס ירידת שורה. ואם אתם לא כותב כותבים ביטויים רגולריים? אז למדתם משהו חדש 🙂

פוסטים נוספים שכדאי לקרוא

תמונה מצוירת של רובוט שמנקה HTML
יסודות בתכנות

סניטציה – למה זה חשוב

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

פתרונות ומאמרים על פיתוח אינטרנט

יישום של nonce על מנת להגן מפני התקפות injection

בפוסט הקודם הסברתי על hash עם CSP על משאבי inline – שזה נחמד ומעולה אבל פחות ישים בעולם האמיתי שבו בדרך כלל התוכן ה-inline (בין

גלילה לראש העמוד