JavaRush /בלוג Java /Random-HE /ביטויים רגולריים ב-Java, חלק 2

ביטויים רגולריים ב-Java, חלק 2

פורסם בקבוצה
אנו מציגים לתשומת לבך תרגום של מדריך קצר לביטויים רגולריים בג'אווה, שנכתב על ידי ג'ף פריזן עבור אתר javaworld . כדי להקל על הקריאה, חילקנו את המאמר למספר חלקים. ביטויים רגולריים ב-Java, חלק 2 - 1ביטויים רגולריים ב-Java, חלק 1
מיזוג טווחים מרובים
אתה יכול למזג טווחים מרובים למחלקת תו טווח אחת על ידי הצבתם זה לצד זה. לדוגמה, המחלקה [a-zA-Z]מתאימה לכל התווים האלפביתיים הלטינים באותיות קטנות או רישיות.

מיזוג טווחים מרובים

אתה יכול למזג טווחים מרובים למחלקת תו טווח אחת על ידי הצבתם זה לצד זה. לדוגמה, המחלקה [a-zA-Z]מתאימה לכל התווים האלפביתיים הלטינים באותיות קטנות או רישיות.

שילוב כיתות אופי

איחוד מחלקות תווים מורכב מכמה מחלקות תווים מקוננות ומתאים לכל התווים באיחוד שנוצר. לדוגמה, הכיתה [a-d[m-p]]מתאימה את התווים מ- aאל dומ- mאל p. שקול את הדוגמה הבאה: java RegexDemo [ab[c-e]] abcdef דוגמה זו תמצא את התווים a, b, c, dו- eשעבורם יש התאמות ב- abcdef:
regex = [ab[c-e]]
input = abcdef
Found [a] starting at 0 and ending at 0
Found [b] starting at 1 and ending at 1
Found [c] starting at 2 and ending at 2
Found [d] starting at 3 and ending at 3
Found [e] starting at 4 and ending at 4

צומת כיתת דמות

ההצטלבות של מחלקות תווים מורכבת מתווים משותפים לכל המחלקות המקוננות ומתאים רק לתווים הנפוצים. לדוגמה, הכיתה [a-z&&[d-f]]תואמת את התווים d, eו f. שקול את הדוגמה הבאה: java RegexDemo "[aeiouy&&[y]]" party שים לב שבמערכת ההפעלה Windows שלי, יש צורך במירכאות כפולות מכיוון שמעטפת הפקודה מתייחסת אליהם &כמפריד פקודה. דוגמה זו תמצא רק את הדמות yשיש לה התאמה ב party:
regex = [aeiouy&&[y]]
input = party
Found [y] starting at 4 and ending at 4

הפחתת כיתות תווים

הפחתת מחלקות תווים מורכבת מכל התווים מלבד אלה הכלולים במחלקות תווים מקוננות, ומתאימה רק לאותם התווים הנותרים. לדוגמה, המחלקה [a-z&&[^m-p]]מתאימה את התווים מ aאל lומאל : דוגמה זו תמצא את התווים qועבורם יש התאמות ב : zjava RegexDemo "[a-f&&[^a-c]&&[^e]]" abcdefgdfabcdefg
regex = [a-f&&[^a-c]&&[^e]]
input = abcdefg
Found [d] starting at 3 and ending at 3
Found [f] starting at 5 and ending at 5

כיתות תווים מוגדרות מראש

מחלקות תווים מסוימות מופיעות בתדירות מספיקה בביטויים רגולריים כדי להצדיק את השימוש בתווים קצרים. המחלקה Patternמציעה מחלקות תווים מוגדרות מראש כקיצורים כאלה. אתה יכול להשתמש בהם כדי לפשט את הביטויים הרגולריים שלך ולמזער שגיאות תחביר. ישנן מספר קטגוריות של מחלקות תווים מוגדרות מראש: java.lang.Characterמאפיינים סטנדרטיים, POSIX ו-Unicode כגון סקריפט, בלוק, קטגוריה ובינארי. הרשימה הבאה מציגה רק את הקטגוריה של כיתות סטנדרטיות:
  • \d: מספר. שווה ערך [0-9].
  • \D: תו לא מספרי. שווה ערך [^0-9].
  • \s: תו רווח לבן. שווה ערך [ \t\n\x0B\f\r].
  • \S: לא תו רווח לבן. שווה ערך [^\s].
  • \w: סמל יוצר מילים. שווה ערך [a-zA-Z_0-9].
  • \W: לא דמות יוצרות מילים. שווה ערך [^\w].
הדוגמה הבאה משתמשת במחלקת תווים מוגדרת מראש \wכדי לתאר את כל תווי המילים בטקסט הקלט: java RegexDemo \w "aZ.8 _" עיין היטב בתוצאות הביצוע הבאות, המראות שתווי נקודה ורווח אינם נחשבים לתווי מילים:
regex = \w
input = aZ.8 _
Found [a] starting at 0 and ending at 0
Found [Z] starting at 1 and ending at 1
Found [8] starting at 3 and ending at 3
Found [_] starting at 5 and ending at 5
מפרידי שורות
תיעוד ה-SDK של המחלקה Patternמתאר את מט-תו הנקודה כמחלקת תו מוגדרת מראש התואמת לכל תו למעט מפרידי שורות (רצפים של תו אחד או שניים המסמנים את סוף השורה). היוצא מן הכלל הוא מצב dotall (עליו נדון בהמשך), שבו נקודות מתאימות גם למפרידי קווים. המחלקה Patternמבדילה בין מפרידי השורות הבאים:
  • תו החזרת כרכרה ( \r);
  • תו newline (סמל לקידום נייר שורה אחת) ( \n);
  • תו החזרת כרכרה מיד אחריו תו חדש ( \r\n);
  • תו השורה הבאה ( \u0085);
  • תו מפריד שורות ( \u2028);
  • סמל מפריד פסקה ( \u2029)

קבוצות שנלכדו

קבוצת הלכידה משמשת לשמירת קבוצת התווים שנמצאה לשימוש נוסף בעת חיפוש לפי דפוס. מבנה זה הוא רצף של תווים המוקפים במטא-תווים בסוגריים ( ( )). כל הדמויות בקבוצה שנלכדה נחשבות כמכלול אחד בעת חיפוש לפי דפוס. לדוגמה, קבוצת הלכידה ( Java) משלבת את האותיות J, a, vו aליחידה אחת. קבוצת לכידה זו מוצאת את כל המופעים של התבנית Javaבטקסט הקלט. עם כל התאמה, התווים המאוחסנים הקודמים Javaמוחלפים בתווים הבאים. ניתן לקנן קבוצות שנתפסו בתוך קבוצות שנלכדו אחרות. לדוגמה, בביטוי רגולרי, (Java( language))קבוצה (language)מקוננת בתוך קבוצה (Java). לכל קבוצת לכידה מקוננת או לא מקוננת מוקצה מספר, החל מ-1, והמספור עובר משמאל לימין. בדוגמה הקודמת, (Java( language))תואם את קבוצת הלכידה מספר 1 ומתאימה (language)לקבוצת הלכידה מספר 2. בביטוי הרגולרי (a)(b), (a)מתאים לקבוצת הלכידה מספר 1 וקבוצת (b)הלכידה מספר 2. ביטויים רגולריים ב-Java, חלק 2 - 2ניתן לגשת מאוחר יותר להתאמות המאוחסנות על ידי קבוצות הלכידה באמצעות הפניות לאחור. הכוונה בתור תו קו נטוי ואחריו תו מספרי המתאים למספר הקבוצה הנלכדת, ההפניה לאחור מאפשרת להתייחס לתווים בטקסט שנלכדה על ידי הקבוצה. קישור נכנס גורם לתואם להתייחס לתוצאת החיפוש המאוחסנת של הקבוצה שנלכדה על סמך המספר ממנה, ולאחר מכן להשתמש בתווים מאותה תוצאה כדי לנסות חיפוש נוסף. הדוגמה הבאה מציגה את השימוש בהפניה לאחור כדי למצוא שגיאות דקדוקיות בטקסט: java RegexDemo "(Java( language)\2)" "The Java language language" דוגמה זו (Java( language)\2)משתמשת בביטוי רגולרי כדי למצוא שגיאה דקדוקית עם מילה כפולה languageמיד אחריה Javaבטקסט הקלט "The Java language language". ביטוי רגולרי זה מציין שתי קבוצות ללכוד: מספר 1 – (Java( language)\2), מתאים Java language languageומספר 2 – (language), המתאים לתו הרווח ואחריו language. ההפניה לאחור \2מאפשרת לראות מחדש את התוצאה המאוחסנת של קבוצה מספר 2 כך שהמתאים יוכל לחפש את המופע השני של רווח ואחריו language, מיד לאחר המופע הראשון של רווח ו- language. תוצאות השידוך RegexDemoהן כדלקמן:
regex = (Java( language)\2)
input = The Java language language
Found [Java language language] starting at 4 and ending at 25

תואמי גבולות

לפעמים צריך לבצע התאמת דפוס בתחילת שורה, בגבולות מילים, בסוף טקסט וכו'. אתה יכול לעשות זאת על ידי שימוש באחד מתאמת הקצה של הכיתה Pattern, שהם מבני ביטוי רגולרי שמחפשים התאמות במיקומים הבאים:
  • ^: תחילת קו;
  • $: סוף שורה;
  • \b: גבול מילים;
  • \B: גבול פסאודו-מילה;
  • \A: תחילת טקסט;
  • \G: סוף המשחק הקודם;
  • \Z: סוף הטקסט, לא כולל מפריד קו נגרר (אם קיים);
  • \z: סוף הטקסט
הדוגמה הבאה משתמשת ^במת-תו מתאמת הגבול כדי למצוא שורות שמתחילות ב- The, ואחריהן אפס או יותר תווי מילה: java RegexDemo "^The\w*" Therefore התו ^מציין ששלושת התווים הראשונים של טקסט הקלט חייבים להתאים לתווי דפוס עוקבים T, hו- e, שלאחריהם ניתן למצוא כל מספר של סמלים יוצרי מילים. הנה התוצאה של הביצוע:
regex = ^The\w*
input = Therefore
Found [Therefore] starting at 0 and ending at 8
מה קורה אם תשנה את שורת הפקודה ל java RegexDemo "^The\w*" " Therefore"? לא תימצא התאמה מכיוון Thereforeשלטקסט הקלט מקדים תו רווח.

התאמות באורך אפס

לפעמים, כשעובדים עם מתאמי קצה, תיתקלו בהתאמות באורך אפס. Совпадение нулевой длиныהוא התאמה שאינה מכילה שום תווים. הם יכולים להתרחש בטקסט קלט ריק, בתחילת טקסט הקלט, אחרי התו האחרון של טקסט הקלט, ובין כל שני תווים של טקסט הקלט. קל לזהות התאמות באורך אפס מכיוון שהם תמיד מתחילים ומסתיימים באותו מיקום. שקול את הדוגמה הבאה: java RegExDemo \b\b "Java is" דוגמה זו מחפשת שני גבולות מילים עוקבים, והתוצאות נראות כך:
regex = \b\b
input = Java is
Found [] starting at 0 and ending at -1
Found [] starting at 4 and ending at 3
Found [] starting at 5 and ending at 4
Found [] starting at 7 and ending at 6
אנו רואים כמה התאמות באורך אפס בתוצאות. עמדות הסיום כאן הן אחת פחות מעמדות ההתחלה, מכיוון שציינתי RegexDemoבקוד המקור ברישום 1 end() – 1. ביטויים רגולריים ב-Java, חלק 2 - 3

מכמתים

מכמת הוא מבנה ביטוי רגולרי שמשייך באופן מפורש או מרומז דפוס לערך מספרי. ערך מספרי זה קובע כמה פעמים לחפש את התבנית. מכמתים מחולקים לחמדנים, עצלנים וסופר-חמדנים:
  • הכמת החמדן ( ?, *או +) נועד למצוא את ההתאמה הארוכה ביותר. אני יכול לשאול X? למצוא מופע אחד או פחות X, X*למצוא אפס התרחשות או יותר X, X+למצוא מופע אחד או יותר X, X{n}למצוא nהתרחשות X, X{n,}למצוא לפחות (ואולי יותר) nמופעים , Xולמצוא X{n,m}לפחות התרחשות nאך לא יותר .mX
  • מכמת העצל ( ??, *?או +?) נועד למצוא את ההתאמה הקצרה ביותר. אתה יכול לציין X??לחיפוש מופע אחד או פחות של X, X*? למצוא אפס או יותר מופעים X, X+?למצוא מופע אחד או יותר X, X{n}?למצוא nהתרחשות X, X{n,}?למצוא לפחות (ואולי יותר) nמופעים X, X{n,m}?ולמצוא לפחות nאך לא יותר מאשר mהתרחשויות X.
  • הכמת החמדני-על ( ?+, *+או ++) דומה לכמת החמדן, אלא שהכמת החמדני-על עושה רק ניסיון אחד למצוא את ההתאמה הארוכה ביותר, בעוד שמכמת החמדן יכול לבצע מספר ניסיונות. ניתן להגדיר X?+למצוא מופע אחד או פחות X, X*+למצוא אפס התרחשות או יותר X, X++למצוא מופע אחד או יותר X, X{n}+למצוא nמופעים של X, X{n,}+למצוא לפחות (ואולי יותר) nמופעים , Xולמצוא X{n,m}+ לפחות nאך לא יותר mמהתרחשויות X.
הדוגמה הבאה ממחישה את השימוש בכמת חמד: java RegexDemo .*ox "fox box pox" להלן התוצאות:
regex = .*ox
input = fox box pox
Found [fox box pox] starting at 0 and ending at 10
הכמת החמדן ( .*) מוצא את הרצף הארוך ביותר של תווים המסתיים ב- ox. היא צורכת את כל טקסט הקלט ואז מתגלגלת לאחור עד שהיא מזהה שטקסט הקלט מסתיים בתווים אלה. שקול עכשיו את המכמת העצל: java RegexDemo .*?ox "fox box pox" התוצאות שלו:
regex = .*?ox
input = fox box pox
Found [fox] starting at 0 and ending at 2
Found [ box] starting at 3 and ending at 6
Found [ pox] starting at 7 and ending at 10
הכמת העצלן ( .*?) מוצא את רצף התווים הקצר ביותר המסתיים ב- ox. זה מתחיל במחרוזת ריקה וצורך בהדרגה תווים עד שהוא מוצא התאמה. ולאחר מכן ממשיך לעבוד עד למיצוי טקסט הקלט. לבסוף, בואו נסתכל על המכמת הסופר-חמדן: java RegexDemo .*+ox "fox box pox" והנה התוצאות שלו:
regex = .*+ox
input = fox box pox
הכמת האקסטרה-greedy ( .*+) לא מוצא התאמות מכיוון שהוא צורך את כל טקסט הקלט ולא נותר מה להתאים oxבסוף הביטוי הרגולרי. בניגוד לכמת החמדן, הכמת הסופר-חמדן אינו מתגלגל לאחור.

התאמות באורך אפס

לפעמים כשעובדים עם מכמים תיתקלו בהתאמות באורך אפס. לדוגמה, השימוש בכמת החמדן הבא מביא למספר התאמות באורך אפס: java RegexDemo a? abaa התוצאות של הפעלת דוגמה זו:
regex = a?
input = abaa
Found [a] starting at 0 and ending at 0
Found [] starting at 1 and ending at 0
Found [a] starting at 2 and ending at 2
Found [a] starting at 3 and ending at 3
Found [] starting at 4 and ending at 3
יש חמישה התאמות בתוצאות הביצוע. למרות שהראשון, השלישי והרביעי צפויים למדי (הם תואמים את המיקומים של שלוש אותיות aב abaa), השני והחמישי עשויים להפתיע אותך. נראה כאילו הם מציינים מה aמתאים bלסוף הטקסט, אבל במציאות זה לא כך. הביטוי הרגולרי a?אינו מחפש bבסוף הטקסט. הוא מחפש נוכחות או היעדרות a. כאשר a?הוא לא מוצא a, הוא מדווח על כך כהתאמה באורך אפס.

ביטויי דגל מקוננים

מתאמים מייצרים כמה הנחות ברירת מחדל שניתן לעקוף אותם בעת קומפילציה של הביטוי הרגולרי לתבנית. נדון בנושא זה בהמשך. ביטוי רגולרי מאפשר לך לעקוף כל אחת מברירות המחדל באמצעות ביטוי דגל מקונן. מבנה ביטוי רגולרי זה מצוין כתו מטא של סוגריים סביב תו מטא של סימן שאלה ( ?), ואחריו אות לטינית קטנה. הכיתה Patternמבינה את ביטויי הדגל המקוננים הבאים:
  • (?i): מאפשר התאמת דפוסים ללא רגישות רישיות. לדוגמה, בעת שימוש בפקודה, java RegexDemo (?i)tree Treehouseרצף התווים Treeתואם לתבנית tree. ברירת המחדל היא חיפוש דפוס תלוי רישיות.
  • (?x): מאפשר שימוש בתווי רווח לבן והערות המתחילות באות המטא בתוך התבנית #. השדכן יתעלם משניהם. לדוגמה, עבור java RegexDemo ".at(?x)#match hat, cat, and so on" matterרצף של תווים matמתאים לתבנית .at. כברירת מחדל, תווים והערות רווחים לבנים אינם מותרים, והמתאם מתייחס אליהם כאל תווים המעורבים בחיפוש.
  • (?s): מאפשר מצב dotall, שבו תו המטא תואם תואם למפרידי שורות בנוסף לכל תו אחר. לדוגמה, הפקודה java RegexDemo (?s). \nתמצא תו חדש. ברירת המחדל היא ההפך מ-dotall: לא יימצאו מפרידי שורות. לדוגמה, הפקודה Java RegexDemo . \nלא תמצא תו חדש.
  • (?m): מפעיל מצב ריבוי שורות, שבו הוא ^מתאים להתחלה ולסוף $של כל שורה. לדוגמה, java RegexDemo "(?m)^abc$" abc\nabcמוצא את שני הרצפים בטקסט הקלט abc. כברירת מחדל, נעשה שימוש במצב של שורה אחת: ^תואם את ההתחלה של כל טקסט הקלט, ומתאים $לסוף שלו. לדוגמה, java RegexDemo "^abc$" abc\nabcמחזירה תגובה שאין התאמות.
  • (?u): מאפשר יישור רישיות רגיש ל-Unicode. דגל זה, בשימוש בשילוב עם (?i), מאפשר התאמת דפוסים ללא רגישות רישיות בהתאם לתקן Unicode. הגדרת ברירת המחדל היא חיפוש תווים תלויי רישיות ותווים US-ASCII בלבד.
  • (?d): מאפשר מצב מחרוזת בסגנון Unix, שבו המתאם מזהה תווים מטא בהקשר ., ^ורק $את מפריד השורות \n. ברירת המחדל היא מצב מחרוזת שאינה בסגנון יוניקס: המתאם מזהה, בהקשר של המטא-תווים לעיל, את כל תווי הקווים המפרידים.
ביטויי דגל מקוננים דומים לקבוצות שנתפסו מכיוון שהדמויות שלהם מוקפות במטא-תווים בסוגריים. בניגוד לקבוצות שנלכדו, ביטויי דגל מקוננים הם דוגמה לקבוצות שאינן נלכדות, שהן מבנה של ביטוי רגיל שאינו לוכד תווי טקסט. הם מוגדרים כרצפים של תווים מוקפים במטא-תווים של סוגריים.
ציון ביטויי דגל מקוננים מרובים
ניתן לציין מספר ביטויי דגל מקוננים בביטוי רגולרי על ידי הצבתם זה לצד זה ( (?m)(?i))) או הצבת האותיות שמגדירות אותם ברצף ( (?mi)).

סיכום

כפי שבטח הבנתם עד עכשיו, ביטויים רגולריים הם שימושיים ביותר והופכים שימושיים עוד יותר ככל שאתם שולטים בניואנסים של התחביר שלהם. עד כה הצגתי לך את היסודות של ביטויים רגולריים וה- Pattern. בחלק 2, נבחן לעומק את ממשק ה-API של Regex ונחקור את השיטות של ה- Pattern, Matcherו- PatternSyntaxException. אני גם אראה לך שני יישומים מעשיים של Regex API שתוכל להשתמש בהם באופן מיידי בתוכניות שלך. ביטויים רגילים ב-Java, חלק 3 ביטויים רגילים ב-Java, חלק 4 ביטויים רגילים ב-Java, חלק 5
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION