פשט את משימות התכנות הנפוצות עם ה-API של Regex
בחלקים 1 ו-2 של מאמר זה, התוודעתם לביטויים רגולריים ול-Regex API. למדת על הכיתהPattern
ועברת על דוגמאות המדגימות מבני ביטוי רגולרי, מהתאמת תבניות פשוטה באמצעות מחרוזות מילוליות ועד להתאמה מורכבת יותר באמצעות טווחים, מתאמי גבולות ומכמתים. בחלק זה ובחלקים הבאים נשקול נושאים שלא כוסו בחלק הראשון, נלמד את השיטות המקבילות של השיעורים Pattern
, Matcher
ו PatternSyntaxException
. תלמד גם שני כלי עזר המשתמשים בביטויים רגולריים כדי להקל על בעיות תכנות נפוצות. הראשון מחלץ הערות מקוד לתיעוד. השני הוא ספרייה של קוד לשימוש חוזר שנועד לבצע ניתוח מילוני - מרכיב חיוני של אסמבלים, מהדרים ותוכנות דומות.
הורדת קוד המקור
אתה יכול לקבל את כל קוד המקור (שנוצר על ידי Jeff Friesen עבור JavaWorld) עבור יישומי ההדגמה במאמר זה מכאן .לימוד ממשק API
Pattern
, Matcher
והם PatternSyntaxException
שלושת המחלקות המרכיבות את ה-API של Regex. כל אחת מהן מספקת שיטות המאפשרות לך להשתמש בביטויים רגולריים בקוד שלך.
שיטות של כיתת Pattern
מופע של מחלקהPattern
הוא ביטוי רגולרי מהול, המכונה גם דפוס. ביטויים רגולריים מורכבים כדי לשפר את הביצועים של פעולות התאמת דפוסים. השיטות הסטטיות הבאות תומכות בהידור.
Pattern compile(String regex)
מרכיב את התוכןregex
לייצוג ביניים המאוחסן בחדשPattern
. שיטה זו מחזירה הפניה לאובייקט אם היא מצליחה, או זורקת חריגPatternSyntaxException
אם מזוהה תחביר ביטוי רגולרי לא חוקי. כל אובייקט של המחלקהMatcher
בשימושPattern
או מוחזר מאובייקט זה משתמש בהגדרות ברירת המחדל שלו, כגון חיפוש תלוי רישיות. כדוגמה, קטע הקודPattern p = Pattern.compile("(?m)^\\.");
יוצר אובייקטPattern
המאחסן ייצוג הידור של ביטוי רגולרי כדי להתאים מחרוזות שמתחילות בתו נקודה.Pattern compile(String regex, int flags)
פותר את אותה בעיה כמוPattern compile(String regex)
, אבל תוך התחשבותflags
: קבוצה של קבועי סיביות עבור דגלי סיביות מסוג OR. המחלקהPattern
מכריזה על קבועיםCANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINES
שניתן לשלב באמצעות OR (לדוגמה,CASE_INSENSITIVE | DOTALL
) ולהעביר אותם כארגומנטflags
.
למעט
CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASS
, קבועים אלו מהווים חלופה לביטויי הדגל המקוננים שהוצגו בחלק 1. אם נתקל בקבוע דגל אחר מאלה שהוגדרו במחלקה Pattern
, השיטה Pattern compile(String regex, int flags)
זורקת חריג java.lang.IllegalArgumentException
. לדוגמה, Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);
שווה ערך לדוגמה הקודמת, כאשר הביטוי הקבוע Pattern.MULTILINE
וביטוי הדגל המקונן (?m)
עושים את אותו הדבר.
Pattern
, יחד עם הדגלים שבהם הוא משתמש. כדי לעשות זאת, אתה יכול לקרוא לשיטות הבאות:
String pattern()
מחזירה את מחרוזת הביטוי הרגולרי המקורית שהורכבה ל-Pattern
.int flags()
מחזירה את דגלי האובייקטPattern
.
Pattern
, הוא משמש בדרך כלל להשגת האובייקט Matcher
לביצוע פעולות התאמת דפוסים. השיטה Matcher matcher(Charsequence input)
יוצרת אובייקט Matcher
שמחפש בטקסט input
התאמה לתבנית אובייקט Pattern
. כאשר נקרא, הוא מחזיר הפניה לאובייקט זה Matcher
. לדוגמה, הפקודה Matcher m = p.matcher(args[1]);
מחזירה Matcher
עבור האובייקט Pattern
שאליו המשתנה מפנה p
.
חיפוש חד פעמי |
---|
שיטת static boolean matches(String regex, CharSequence input) המחלקה Pattern מאפשרת לחסוך ביצירת אובייקטים Pattern וחיפוש Matcher חד פעמי באמצעות תבנית. שיטה זו מחזירה true אם input הדפוס מותאם regex , אחרת היא מחזירה false. אם הביטוי הרגולרי מכיל שגיאת תחביר, השיטה זורקת חריגה PatternSyntaxException . לדוגמה, System.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only")); מדפיס true , המאשר שהביטוי all lowercase letters and whitespace only מכיל רק רווחים ותווים קטנים. |
פיצול טקסט
רוב המפתחים כתבו לפחות פעם אחת קוד כדי לפצל טקסט קלט לחלקים המרכיבים שלו, כמו המרת חשבון עובד מבוסס טקסט לקבוצה של שדות. הכיתהPattern
מספקת את היכולת לפתור בצורה נוחה יותר את המשימה המייגעת הזו באמצעות שתי שיטות פיצול טקסט:
-
השיטה
String[] split(CharSequence text, int limit)
מתפצלתtext
לפי ההתאמות שנמצאו לתבנית האובייקטPattern
ומחזירה את התוצאות במערך. כל רכיב מערך מציין רצף טקסט המופרד מהרצף הבא על ידי קטע טקסט תואם דפוס (או סוף טקסט). הרכיבים של המערך נמצאים באותו סדר שבו הם מופיעים בtext
.בשיטה זו, מספר רכיבי המערך תלוי בפרמטר
limit
, אשר שולט גם במספר ההתאמות שיימצאו.- ערך חיובי מחפש לא יותר מהתאמות
limit-1
ואורך המערך אינו עולה עלlimit
אלמנטים. - אם הערך שלילי, כל ההתאמות האפשריות מתבצעות, ואורך המערך יכול להיות שרירותי.
- אם הערך הוא אפס, כל ההתאמות האפשריות מתבצעות, אורך המערך יכול להיות שרירותי, ושורות ריקות בסוף נמחקות.
- ערך חיובי מחפש לא יותר מהתאמות
- השיטה
String[] split(CharSequence text)
קוראת למתודה הקודמת עם 0 כארגומנט הגבול ומחזירה את תוצאת הקריאה שלה.
split(CharSequence text)
לפתרון בעיית פיצול חשבון עובד לשדות נפרדים של שם, גיל, כתובת דואר ומשכורת:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i]);
הקוד למעלה מתאר ביטוי רגולרי למציאת תו פסיק מיד ואחריו תו רווח בודד. להלן תוצאות ביצועו:
John Doe
47
Hillsboro Road
32000
פרדיקטים של תבניות וממשק ה-API של Streams
ב-Java 8,Pattern
שיטה הופיעה במחלקה . שיטה זו יוצרת פרדיקט (פונקציה בעלת ערך בוליאני) המשמשת כדי להתאים את התבנית. השימוש בשיטה זו מוצג בקטע הקוד הבא: Predicate
asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
קוד זה יוצר רשימה של שמות שפות תכנות, ולאחר מכן מרכיב דפוס כדי למצוא את כל השמות שמתחילים באות c
. שורת הקוד האחרונה לעיל מיישמת קבלת זרם סדרתי של נתונים עם רשימה זו כמקור. הוא מגדיר מסנן באמצעות פונקציה בוליאנית asPredicate()
שמחזירה אמת כשהשם מתחיל באות c
וחוזרת דרך הזרם, מדפיסה שמות תואמים לפלט סטנדרטי. שורה אחרונה זו מקבילה ללולאה הרגילה הבאה, המוכרת מאפליקציית RegexDemo מחלק 1:
for (String progLang: progLangs)
if (p.matcher(progLang).find())
System.out.println(progLang);
שיטות מחלקות התאמה
מופע של המחלקהMatcher
מתאר מנגנון לביצוע פעולות התאמת דפוסים על רצף של תווים על ידי פרשנות הביטוי הרגולרי המהודר של המחלקה Pattern
. אובייקטים של המחלקה Matcher
תומכים בסוגים שונים של פעולות חיפוש דפוסים:
-
השיטה
boolean find()
מחפשת בטקסט הקלט עבור ההתאמה הבאה. שיטה זו מתחילה בסריקה בתחילת הטקסט שצוין או בתו הראשון לאחר ההתאמה הקודמת. האפשרות השנייה אפשרית רק אם הקריאה הקודמת לשיטה זו החזירה true והפותר לא אופס. בכל מקרה, אם החיפוש מצליח, הערך הבוליאני true מוחזר. דוגמה לשיטה זו ניתן למצוא בחלקRegexDemo
1. -
השיטה
boolean find(int start)
מאפסת את המתאים ומחפשת בטקסט את ההתאמה הבאה. הצפייה מתחילה מהמיקום שצוין על ידי הפרמטרstart
. אם החיפוש מצליח, הערך הבוליאני true מוחזר. לדוגמה,m.find(1);
סורק את הטקסט החל ממיקום1
(מתעלמים ממיקום 0). אם הפרמטרstart
מכיל ערך שלילי או ערך גדול מאורך טקסט התואם, השיטה זורקת חריגהjava.lang.IndexOutOfBoundsException
. -
השיטה
boolean matches()
מנסה להתאים את כל הטקסט לתבנית. הוא מחזיר ערך בוליאני true אם כל הטקסט תואם לתבנית. לדוגמה, הקודPattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());
יוצאfalse
מכיוון שהתו!
אינו תו מילה. -
השיטה
boolean lookingAt()
מנסה להתאים את הטקסט שצוין לתבנית. שיטה זו מחזירה אמת אם חלק כלשהו מהטקסט תואם לתבנית. שלא כמו השיטהmatches();
, כל הטקסט לא חייב להתאים לתבנית. לדוגמה,Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());
הוא יפיק פלטtrue
, מכיוון שתחילת הטקסטabc!
מורכבת רק מתווים יוצרי מילים.
Pattern
, אובייקטי כיתה Matcher
שומרים על מידע מצב. לפעמים ייתכן שיהיה עליך לאפס את התאמת כדי לנקות מידע זה לאחר סיום חיפוש הדפוס. השיטות הבאות זמינות לאיפוס הפותר:
-
השיטה
Matcher reset()
מאפסת את מצב המתאם, כולל המיקום שיש להוסיף לסוף (איפוס ל-0). פעולת חיפוש הדפוס הבאה מתחילה בתחילת הטקסט המתאים. מחזירה הפניה לאובייקט הנוכחיMatcher
. לדוגמה,m.reset();
מאפס את הפותר שאליו מתייחסm
. -
השיטה
Matcher reset(CharSequence text)
מאפסת את מצב הפותר ומגדירה את טקסט הפותר החדש לtext
. פעולת חיפוש הדפוס הבאה מתחילה בתחילת טקסט התאמת החדש. מחזירה הפניה לאובייקט הנוכחיMatcher
. לדוגמה,m.reset("new text");
מאפס את הפותר המפנהm
ומגדיר את טקסט הפותר החדש ל"new text"
.
הוספת טקסט לסוף
המיקום של התואם שיש להוסיף לסוף מציין את תחילת הטקסט המתואם שצורף לסוף אובייקט הסוגjava.lang.StringBuffer
. השיטות הבאות משתמשות בעמדה זו:
-
השיטה
Matcher appendReplacement(StringBuffer sb, String replacement)
קוראת את תווי הטקסט המתואם ומצרפת אותם לסוף האובייקטStringBuffer
שאליו מתייחס הארגומנטsb
. שיטה זו מפסיקה לקרוא את התו האחרון שלפני התאמת התבנית הקודמת. לאחר מכן, השיטה מוסיפה את התווים מהאובייקט מהסוגString
שאליו מתייחס הארגומנטreplacement
לסוף האובייקטStringBuffer
(המחרוזתreplacement
עשויה להכיל הפניות לרצפי טקסט שנלכדו במהלך החיפוש הקודם; אלה מצוינים באמצעות התווים($)
ומספרי הקבוצות הנלכדים). לבסוף, השיטה מגדירה את הערך של מיקום התואם שיצורף למיקום התו האחרון המותאם פלוס אחד, ולאחר מכן מחזירה הפניה למשואם הנוכחי. -
השיטה
StringBuffer appendTail(StringBuffer sb)
מוסיפה את כל הטקסט לאובייקטStringBuffer
ומחזירה הפניה לאותו אובייקט. לאחר הקריאה למתודה האחרונהappendReplacement(StringBuffer sb, String replacement)
, קרא למתודהappendTail(StringBuffer sb)
כדי להעתיק את הטקסט הנותר לאובייקטStringBuffer
.
השיטה Matcher appendReplacement(StringBuffer sb, String replacement)
זורקת חריגה java.lang.IllegalStateException
אם התואם עדיין לא מצא התאמה או שניסיון חיפוש קודם נכשל. זה זורק חריג IndexOutOfBoundsException
אם השורה replacement
מציינת קבוצת לכידה שאינה בתבנית).
קבוצות שנלכדו |
---|
כפי שאתה זוכר מחלק 1, קבוצת לכידה היא רצף של תווים מוקפים בסוגריים ( () ) תווים מטאתיים. מטרת המבנה הזה היא לאחסן את התווים שנמצאו לשימוש חוזר מאוחר יותר במהלך התאמת דפוסים. כל הדמויות מהקבוצה שנלכדה נחשבות כמכלול אחד במהלך חיפוש הדפוס. |
appendReplacement(StringBuffer sb, String replacement)
and appendTail(StringBuffer sb
כדי להחליף את כל המופעים של רצף התווים בטקסט המקור cat
ב- caterpillar
:
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
שימוש בקבוצה שנלכדה והפניה אליה בטקסט החלופי מורה לתוכנית להוסיף erpillar
לאחר כל מופע של cat
. התוצאה של ביצוע קוד זה נראית כך: one caterpillar, two caterpillars, or three caterpillars on a fence
מחליף טקסט
המחלקהMatcher
מספקת לנו שתי שיטות להחלפת טקסט, משלימות ל- appendReplacement(StringBuffer sb, String replacement)
. באמצעות שיטות אלה, תוכל להחליף את המופע הראשון של [הטקסט שהוחלף] או את כל המופעים:
-
השיטה
String replaceFirst(String replacement)
מאפסת את ה-matcher, יוצרת אובייקט חדשString
, מעתיקה את כל התווים של טקסט ה-matcher (עד ההתאמה הראשונה) למחרוזת זו, מוסיפה את התווים לסוף שלהreplacement
, מעתיקה את שאר התווים למחרוזת ומחזירה אובייקטString
(המחרוזתreplacement
יכולה להכיל הפניות לאלו שנלכדו במהלך רצפי טקסט החיפוש הקודמים באמצעות סמלי דולרים ומספרי קבוצה שנלכדו). -
השיטה
String replaceAll(String replacement)
פועלת בדומה לשיטהString replaceFirst(String replacement)
, אך מחליפהreplacement
את כל ההתאמות שנמצאו בתווים מהמחרוזת.
\s+
מחפש תו רווח אחד או יותר בטקסט הקלט. להלן, נשתמש בביטוי הרגולרי הזה ונקרא לשיטה replaceAll(String replacement)
להסרת רווחים כפולים:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем \t\t лишние пробелы. ");
System.out.println(m.replaceAll(" "));
להלן התוצאות: Удаляем лишние пробелы.
ביטויים רגילים ב-Java, חלק 4 ביטויים רגילים ב-Java, חלק 5
GO TO FULL VERSION