מדריך לבריחת תווים ב- Java RegExps

1. סקירה כללית

ממשק ה- API של ביטויים רגילים ב- Java, java.util.regex נמצא בשימוש נרחב להתאמת תבניות. כדי לגלות עוד, תוכלו לעקוב אחר מאמר זה.

במאמר זה נתמקד בבריחה מדמויות עם ביטוי קבוע ונראה כיצד ניתן לעשות זאת בג'אווה.

2. תווי RegExp מיוחדים

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

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

המטא-תווים שבדרך כלל אנו צריכים לברוח באופן זה הם:

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

בדיקה זו מראה כי עבור מחרוזת קלט נתונה פוף כאשר התבנית foo. (foo המסתיים בתו נקודה) תואם, הוא מחזיר ערך של נָכוֹן מה שמעיד על כך שההתאמה מוצלחת.

@Test הציבור בטל givenRegexWithDot_whenMatchingStr_thenMatches () {String strInput = "foof"; מחרוזת strRegex = "foo."; assertEquals (true, strInput.matches (strRegex)); }

אתה יכול לתהות מדוע ההתאמה מוצלחת כאשר אין תו נקודה (.) בקלט חוּט?

התשובה היא פשוטה. הנקודה (.) היא מטא-אופי - המשמעות המיוחדת של הנקודה כאן היא שיכולה להיות 'כל דמות' במקומה. לכן ברור כיצד התאמה קבעה שנמצאת התאמה.

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

איך נתמודד עם מצב כזה? התשובה היא: עלינו לברוח מדמות הנקודה (.) כדי שלא תתעלם ממשמעותה המיוחדת.

בואו לחפור בזה בפירוט רב יותר בסעיף הבא.

3. בריחה מדמויות

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

בואו נראה מה הם:

  1. הקדימו מטא-דמות עם קו נטוי אחורי (\)
  2. צרף מטא-דמות עם \ ש ו \ ה

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

3.1. בריחה באמצעות קו נטוי אחורי

זו אחת הטכניקות שבהן אנו יכולים להשתמש כדי לברוח מטא-תווים בביטוי קבוע. עם זאת, אנו יודעים כי הדמות הנטויה לאחור היא דמות בריחה בג'אווה חוּט גם מילוליות. לכן, עלינו להכפיל את התו האחורי כאשר אנו משתמשים בו כדי להקדים כל תו (כולל התו \ עצמו).

מכאן שבדוגמה שלנו, עלינו לשנות את הביטוי הרגולרי כפי שמוצג במבחן זה:

@Test הציבור בטל שניתןRegexWithDotEsc_whenMatchingStr_thenNotMatching () {String strInput = "foof"; מחרוזת strRegex = "foo \."; assertEquals (false, strInput.matches (strRegex)); }

כאן, דמות הנקודה נמלטת, כך שהשידוך פשוט מתייחס אליה כנקודה ומנסה למצוא תבנית שמסתיימת בנקודה (כלומר. foo.).

במקרה זה הוא חוזר שֶׁקֶר מאחר ואין התאמה בקלט חוּט עבור הדפוס הזה.

3.2. בריחה באמצעות \ Q & \ E

לחלופין, אנו יכולים להשתמש \ ש ו \ ה לברוח מהאופי המיוחד. \ ש מציין שכל התווים עד \ ה צריך להימלט ו \ ה אומר שאנחנו צריכים לסיים את הבריחה שהתחילה איתה \ ש.

זה רק אומר שכל מה שביניהם \ ש ו \ ה יימלט.

במבחן המוצג כאן, לְפַצֵל() של ה חוּט מחלקה עושה התאמה באמצעות הביטוי הרגולרי המסופק לה.

הדרישה שלנו היא לפצל את מחרוזת הקלט בתו הצינור (|) למילים. לכן, אנו משתמשים בדפוס ביטוי רגולרי לשם כך.

אופי הצינור הוא מטא-אופי שצריך להימלט ממנו בביטוי הרגולרי.

כאן הבריחה נעשית על ידי הצבת דמות הצינור בין \ ש ו \ ה:

@Test public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits () \ E "; assertEquals (4, strInput.split (strRegex) .length); 

4. ה דפוס.ציטוט (מחרוזת ש) שיטה

שיטת התבנית. ציטוט (מחרוזת S) ב java.util.regex.Pattern class ממיר דפוס ביטוי קבוע נתון חוּט לתבנית מילולית חוּט. פירוש הדבר שכל המטא-תווים בקלט חוּט מתייחסים אליהם כאל דמויות רגילות.

שימוש בשיטה זו תהיה חלופה נוחה יותר משימוש \ ש & \ ה כשהוא עוטף את הנתון חוּט איתם.

בואו נראה שיטה זו בפעולה:

@ מבחן הריק פומבי שניתןRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits () סרגל

במבחן המהיר הזה, ה- Pattern.quote () משתמשים בשיטה כדי לברוח מתבנית ה- regex הנתונה ולהפוך אותה ל- a חוּט מילולית. במילים אחרות, זה בורח מכל הדמויות המצויות בתבנית regex עבורנו. זה עושה עבודה דומה לזה \ ש & \ ה.

דמות הצינור נמלטת על ידי Pattern.quote () שיטה ו לְפַצֵל() מפרש את זה כ- חוּט מילולי לפיו הוא מחלק את הקלט.

כפי שאנו רואים, זו גישה הרבה יותר נקייה וגם המפתחים לא צריכים לזכור את כל רצפי הבריחה.

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

5. דוגמאות נוספות

בואו נסתכל איך החלף הכל() שיטה של java.util.regex.Matcher עובד.

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

תאר לעצמך שיש לנו קלט עם מספר מופעים של ה- $ אופי. התוצאה אותה אנו רוצים לקבל היא אותה מחרוזת עם ה- $ דמות שהוחלפה ב- £.

מבחן זה מדגים כיצד התבנית $ מועבר מבלי להימלט:

@Test public void givenRegexWithDollar_whenReplacement_thenNotReplace () {String strInput = "נתתי 50 $ לאחי." + "הוא קנה ממתקים תמורת 35 דולר. עכשיו נותרו לו 15 דולר."; מחרוזת strRegex = "$"; מחרוזת strReplacement = "£"; פלט מחרוזת = "נתתי 50 פאונד לאחי." + "הוא קנה ממתקים תמורת 35 פאונד. עכשיו נותרו לו 15 פאונד."; תבנית p = Pattern.compile (strRegex); התאמה m = p.matcher (strInput); assertThat (פלט, לא (equalTo (m.replaceAll (strReplacement)))); }

המבחן טוען כי $ אינו מוחלף כהלכה על ידי £.

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

@Test public void givenRegexWithDollarEsc_whenReplacement_thenRplace () {String strInput = "נתתי 50 $ לאחי." + "הוא קנה ממתקים תמורת 35 דולר. עכשיו נותרו לו 15 דולר."; מחרוזת strRegex = "\ $"; מחרוזת strReplacement = "£"; פלט מחרוזת = "נתתי 50 פאונד לאחי." + "הוא קנה ממתקים תמורת 35 פאונד. עכשיו נותרו לו 15 פאונד."; תבנית p = Pattern.compile (strRegex); התאמה m = p.matcher (strInput); assertEquals (פלט, m.replaceAll (strReplacement)); }

שים לב ל \\$ כאן, מה שעושה את הטריק בכך שהוא בורח מה- $ אופי ותואם בהצלחה את התבנית.

6. מסקנה

במאמר זה בחנו תווים בורחים בביטויים רגולריים בג'אווה.

דנו מדוע צריך להימלט מביטויים קבועים, ובדרכים השונות בהן ניתן להשיג.

כמו תמיד, ניתן למצוא את קוד המקור הקשור למאמר זה ב- GitHub.