RegExp - מדריך מעשי לעבודה עם ביטויים רגולריים בJS


  • תכנות

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

    רקע וסקירה טכנית:

    בJS, יש שתי דרכים ליצור ביטוי רגלורי:
    "ליטרלית" – מופע בקוד, שזה נעשה ע"י טקסט מוקף ב/ למשל /[a-z]/.
    דינמית – יצירת מופע עם new RexExp שמקבל כפרמטר מחרוזת טקסט.

    ההבדל בין הדרכים הוא פשוט: מתי שתבנית החיפוש היא סטטית וידועה מראש בעת כתיבת הקוד נכתוב ליטרלית כי "למה לא". אבל אם תבנית החיפוש היא דינמית מקלט משתמש או קלט אחר, נהיה מוכרחים ליצור ע"י new RegExp.
    בשתי המקרים נוצר האובייקט RegExp שהוא פשוט מאוד. יש לו שתי מתודות: exec, וtest. זהו.
    (יש לו גם שמירת המיקום בו הוא אוחז בחיפוש, נמחיש זאת עוד מעט).
    למחלקה string יש כמה מתודות חשובות שיכולות לקבל כפרמטר אובייקט RegExp:
    match, search, replace, split.

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

    יצירת RegExp בשתי הדרכים:

     var r = /[a-z]/;
     var r2 = new RegExp("[a-z]");
    

    דגלים

    יצירה עם דגלים:

     var r = /[a-z]/g;
     var r2 = new RegExp("[a-z]", "g");
    

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

     console.log(/1/.flags);
     console.log(/1/.global);
     console.log(/1/.ignoreCase);
    

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

    מתודות של הRegExp

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

     /[0-9]+/.test("656565");
    

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

     /^[0-9]+$/.test("656565");
    

    זה נקרא ללמוד מטעויות :).

    exec:

    ראשית, המתודה הזו רלוונטית רק אם החיפוש הוא גלובלי (דגל הg). שנית, היא עשויה לקריאה בלבד, אם יש רצון להפיק מחרוזת טקסט שונה בהתבסס על התוצאות יש להשתמש רק בreplace שיובא בהמשך.
    בחיפוש גלובלי ייתכנו כמה תוצאות בקלט בודד. למשל הביטוי /[0-9]/ יניב שלושה תוצאות בטקסט "589".
    המתודה exec שמקבלת כפרמטר את טקסט הקלט, מפעילה כל פעם איתור של התוצאה הבאה, ובמידה ונמצאה תוצאה זה מחזיר מערך שמייצג את התוצאה שנמצאה (למה מערך אם זה תוצאה בודדת? בהמשך נראה), ויחד עם זאת מעדכן משתנה בשם lastIndex במופע הRegExp, ככה שפעם הבאה שהוא יופעל הוא יחפש רק משם ואילך ולא יחזיר את אותה התוצאה (נכון, אפשר לנצל זאת כדי לחפש באופן יזום ממקום מסויים במחזרות). במידה ולא נמצאה תוצאה, זה מחזיר null.
    דוגמא:

     var exp = /[0-9]/g;
     var text = "abc123";
     exp.exec(text); 
     console.log(exp.lastIndex); //print 4
    

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

     var result;
     var exp = /[0-9]/g;
     while((result = exp.exec(text)) != null){
         //...
     }
    

    קוד מצויין.
    אבל הקוד הזה ייתן לולאה אין סופית:

     var result;
     while((result =ma /[0-9]/g.exec(text)) != null){
         //...
     }
    

    הסבר: הביטוי הרגולרי נוצר פה מחדש בכל איטרציה של הלולאה ע"י הליטרל /[0-9]/g. ממילא תמיד מוחזרת התוצאה הראשונה, שהרי הlastIndex של RegExp חדש הוא 0, ובצדק.

    בע"ה ההמשך יהיה על המתודות של String.


  • תכנות

    מתודות של String שעובדות עם Regex
    כאמור באובייקט סטרינג יש ארבעה מתודות שעובדים עם regex, אני אסכם אותם בקיצור נמרץ:
    search - מקבלת טקסט רגיל או ביטוי רגלורי ואם ישנה התאמה כל שהיא היא מחזירה את המיקום שלה. המתודה הזו עשויה למקרים שtest לא מספיק כי אנחנו רוצים לדעת איפה התוצאה, אבל לא חשוב לנו הקבוצות.
    split - מפצלת טקסט לאיברי מערך. היא מקבלת טקסט או ביטוי רגולרי.
    match - אם הביטוי הוא לא גלובלי, הא מחזירה בדיוק תוצאה זהה לexec - מערך שמייצג את התוצאה הראשונה. אם הוא גלובלי היא מחזירה מערך של כלל התוצאות, אבל רק כטקסט - מפסידים את מידע הקבוצות.
    replace - זו המתודה החשובה ביותר שתומכת בביטויים רגולריים.
    המתודה הזו מקבלת שתי פרמטרים, הראשון ביטוי לחיפוש והשני ביטוי או פוקנציה מותאמת שתחליף את המופע/ים שיימצאו. היא לא משנה את טקסט המקור אלא מחזירה טקסט חדש.
    הפרמטר הראשון יכול להיות טקסט רגיל או ביטוי רגולרי. במידה והפרמטר הראשון הוא טקסט, אז החיפוש הוא תמיד גלובלי - כל התוצאות יוחלפו, ובמידה וזה ביטוי רגולרי זה תלוי בדגל הg - אם הוא איננו זה יחליף רק את המופע הראשון.

    פה נגמרת הסקירה ומההודעה הבאה יהיה דוגמאות שימוש.


 

בא תתחבר לדף היומי!