Regex - ביטויים רגולריים - קבוצות

פרק שני בסדרת Regex - ביטויים רגולריים

Authors
  • Name
    Dovid
    Published on
    Twitter

Escap - ביטול משמעות תו מיוחד

לפעמים אנחנו צריכים לחפש למשל נקודה או סוגריים וכדומה. והתוים הללו לא מתפרשים כמשמעם שהרי יש להם משמעות מיוחדת בregex. מה עושים? קוראים לזה escaping וזה מתבצע בregex ע"י לוכסן הפוך (ההוא של וינדוס בנתיבי הקבצים, ההפוך משל הכתובות אינטרנט) מקדים. למשל חיפוש . יחפש נקודה ולא תו כלשהוא. שימו לב, הregex בנוי בצורה מאוד עקבית, וממילא כל תו מיוחד שנמצא בקונטקסט חסר משמעות (מהמשמעות המיוחדת) הופך אוטומטית לתו רגיל ופטור מאסקייפ, זה חוסך המון! למשל - מקף, בתוך סוגריים מרובעות הוא מסמל טווח בין שתי תוים. אם נרצה לכלו את תו המקף, נשים אותו פשוט ראשון או אחרון (בכל מצייני הכמות, אפשר לשים אותם ראשונים). אותו דבר סוגריים מרובעות שמשמעותם קבוצת תווים אפשרית, די בכך שנבטל או נשמיט את משמעות הסוגר הפותח, שבן זוגו הסוגר יהפך לרגיל. וכן הלאה.

חלופות - OR

אם אנחנו רוצים תו מבין שתיים אנחנו עושים ככה [אב] שזה אומר או א' או ב'. אבל אם אנחנו רוצים לתת שתיאפשרויות לרצף של יותר מתו בודד, למשל לחפש אור או מנורה, נכתוב עמוד כזה | בין האפשרויות, ככה: אור|מנורה. דוגמה מעשית יותר - https?|ftp זה יאתר או ftp או http (ויש s אופציונלית ע"י הסימן שאלה שאחריה). בשביל לקבץ אפשרויות יש להשתמש בסוגריים, אבל חובה קודם להכיר את המושג הבא, קבוצות.

קבוצות

קבוצות זה קיבוץ אלמנטים בחיפוש שלנו, המשמעות של הקיבוץ הזה היא בשביל התייחסות אל הקבוצה בהמשך ב1)ביטוי החיפוש עצמו, 2) תוצאה 3)ביטוי ההחלפה. אני אתייחס בעיקר ל3, שזה מה שקורה בהחלפה. אם אנו רוצים להחליף כל רצף מספרי במסמך למוקף סולמיות. אז אנו מחפשים \d+ אך במה מחליפים? אז יש שתי דרכים להתייחס לכלל התוצאה בביטוי ההחלפה. או $0, או \0. אז אנחנו נכתבו במקרה שלנו בהחלפה #$0#, הנה דוגמה. בינתיים לא היינו צריכים קבוצות (אם כי $0 משמעותו קבוצה אפס, וזה מתייחס תמיד לכלל הטקסט של התוצאה). אך כעת משימה סבוכה יותר, אנחנו צריכים למצוא מספרים מוקפים במרכאות ולעטוף את המספר שבתוכם בסולמיות. כלומר יש לנו "123" והרצוי כעת הוא "#123#" כמובן שהמספר לא תמיד 123... אז אנחנו מחפשים "\d+", ופה בהחלפה אנחנו צריכים מתכון כזה: מרכאות, סולמית, המספר שהיה בין המרכאות, סולמית מרכאות. פה יעזור לנו קיבוץ. נכתוב ככה: "(\d+)" ונחליף ככה: "#$1#". דוגמה. בזה שעשינו סוגריים מסביב ה\d+ הגדרנו שכל מה שעונה על הקירטריונים המוקפים מתוך התוצאה, יוגדרו כתת קבוצה בתוצאה. וכעת בהחלפה, יכלנו להתייחס לקבוצה הזו ע"י $1. מה זה ה$1? ובכן דולר בביטוי ההחלפה שמגיע מייד אחריו מספר, משמש כשומר מקום לקבוצה מהתוצאה (שהוגדרה בביטוי החיפוש). בגלל שבביטוי החיפוש יכולים להיות כמה קבוצות, אז המספר מציין את מספר הקבוצה לפי מיקומה (הראשונה 1 וכו'. 0 מתייחס לכלל הביטוי כולו).

לפעמים נקבץ אלמנטים לא בשביל להפוך אותם לקבוצה, אלא כדי להחיל עליהם כמות, כמו {}, כוכבית, פלוס, סימן שאלה, או | (המקרה הכי נפוץ זה סימן | שנותן שתי אופציות אבל רק בחלק מהביטוי או סימן שאלה שהופך קבוצת אלמנטים שלמה לאופציונלית). במקרה כזה, ייתכן שזה יפריע לנו בכלל העובדה שזה הופך לקבוצה (למה? לא יודע, אולי בגלל שיש הרבה קבוצות בביטוי שלנו וצריך כבר לאחוז ראש. אם כי הגיוני בכזה מצב לעשות קבוצות שמיות שמייד אסביר). בשביל לקבץ אלמנטים לא על מנת להפכם לקבוצה אלא כדי להכיל עליהם אופרטורי כמות או |, ניתן לכתוב מייד בתחילת הסוגריים ?:, זה נקרא non-capturing-group, הנה דוגמה של קיבוץ (הירוק מורה על קבוצה), והנה אחרי נטרול של הקבוצה.

קבוצות עם שם

(מממ, לא קיים בJS, אתכם הסליחה (גם לא בES8 למיטב ידיעתי, חבל. עריכה: זה מגיע בES2018). אבל נמצא כמדומני בכל הפלטפורמות האחרות). לעיתים, זה לא נח לעבוד עם קבוצות לפי אינדקס. גם צריך לאחוז ראש את הסדר, גם במקרה שהביטוי מטופל בקוד הוא הופך קשה לתחזוקה כי כל שינוי בביטוי מחייב היערכות בהתייחסות, וגם לפעמים כל הסדר משתנה מתוצאה לאחרת כי אחת הקבוצות נמצאת במקטע אופציונלי. בשביל זה יש אופציה לתת שמות לקבוצות. זה נורא פשוט, בתחילת הסוגריים שמים סימן שאלה ואחריו סוגריים זויתיות שבתוכם שם הקבוצה - "מצוות (סוכה|לולב|שופר)" נכתוב "מצוות (?<מצוה>סוכה|לולב|שופר)" ואח"כ נוכל להתייחס לקבוצה הזאת באופן שמי, למשל בהחלפה במקום $1, נכתוב ${מצוה}. הנה דוגמה.

סימני עגינה ^-$

אם נרצה לחפש מילה שלמה, למשל סוכה ולא בסוכה, ולא מהסוכה, אז נקדים לה רווח. אלא שאז נאבד את המקרה בה היא מופיעה מייד בתחילת הטקסט. נוכל לציין שלפניה יש או תו רווח או את תחילת הטקסט ע"י סימן העגינה של תחילת הטקסט - ^. נכתוב ככה (^| )סוכה. אותו דבר לגבי הסיום, נכול לדרוש שיש אחריו רווח או סוף הטקסט ע"י הסימן $, (^| )סוכה( |$). שכיח בתכנות שרוצים לבדוק את כלל המחרוזת ולא למצוא רק התאמה בתוכה, ואז כותבים משהו כמו ^סוכה$ - משמעות הביטוי היא התאמה לכלל טקסט הבדיקה, שהרי נכללים בו אין ההתחלה והן סיום הטקסט. כמו"כ בשביל לבדוק מתחיל ב ונגמר ב גם כותבים את אחד מתווי העגינה הללו. למשל באינפוט של טלפון בhtml נוכל לדרוש התאמה לרגקס ^05\d-\d{7}$. נ.ב. יש סימן מיוחד שמסמן סוף\תחילת מילה, והוא \b. הוא בעצם קיצור ל: או רווח או קצה הטקסט (התחלה או סיום) או פסיק וכו'. יש לדבר הזה בעיה קטנה, זה לא עובד בשום שפה חוץ מאנגלית...

בפוסט הבא נדבר על הדגלים - regex flags.