ברוך הבא לביטויים רגולריים ב-Java. יש להם גם את השם Regex ב-Java. כשהתחלתי לתכנת, ביטויים רגולריים ב-Java היו סיוט עבורי. המדריך הזה מיועד לעזור לך להתמקם בביטויים רגולריים ב-Java. אני גם אחזור לכאן לעדכן את למידת ביטויים הרגולריים שלי ב-Java.
ביטויים רגולריים ב-Java
הביטוי הרגולרי ב-Java מגדיר תבנית עבור מחרוזת. ביטויים רגולריים ניתן להשתמש בהם לחיפוש, עריכה או עיבוד טקסט. ביטוי רגולרי אינו תלוי בשפה אך יש הבדילו קצת בין השפות. ביטויים רגולריים ב-Java הם הכי דומים לשפת Perl. כיתות ה-Regex ב-Java קיימות בחבילה
java.util.regex
המכילה שלוש כיתות:
- Pattern: אובייקט
Pattern
הוא הגרסה הממומנת של ביטוי הרגולרי. כיתת Pattern אין לה בנאי ציבורי ואנו משתמשים בשיטת ה-compile
הציבורית שלה כדי ליצור את אובייקט ה-pattern על ידי מעבר של ארגומנט ביטוי הרגולרי. - התאמן:
Matcher
הוא אובייקט מנוע ה-regex של ג'אווה שמתאים את דפוס המחרוזת הנתון עם אובייקט הדפוס שנוצר. מחלקת Matcher אין לה בנאי ציבורי ואנו מקבלים אובייקט Matcher באמצעות שיטת ה-matcher
של אובייקט הדפוס שמקבלת את מחרוזת הקלט כארגומנט. אחר כך אנו משתמשים בשיטתmatches
שמחזירה תוצאת בוליאנית בהתבסס על תאימת מחרוזת הקלט לדפוס ה־regex או לא. - PatternSyntaxException:
PatternSyntaxException
משולכת אם תחביר הביטוי הרגיל אינו נכון.
בואו נסתכל על דוגמת תוכנית regex של ג'אווה.
package com.journaldev.util;
import java.util.regex.*;
public class PatternExample {
public static void main(String[] args) {
Pattern pattern = Pattern.compile(".xx.");
Matcher matcher = pattern.matcher("MxxY");
System.out.println("Input String matches regex - "+matcher.matches());
// ביטוי רגיל רע
pattern = Pattern.compile("*xx*");
}
}
כאשר אנו מפעילים את תוכנית דוגמת regex של ג'אווה זו, אנו מקבלים את הפלט הבא.
Input String matches regex - true
Exception in thread "main" java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0
*xx*
^
at java.util.regex.Pattern.error(Pattern.java:1924)
at java.util.regex.Pattern.sequence(Pattern.java:2090)
at java.util.regex.Pattern.expr(Pattern.java:1964)
at java.util.regex.Pattern.compile(Pattern.java:1665)
at java.util.regex.Pattern.(Pattern.java:1337)
at java.util.regex.Pattern.compile(Pattern.java:1022)
at com.journaldev.util.PatternExample.main(PatternExample.java:13)
מאחר וביטוי הרגיל של ג'אווה נוגע למחרוזת, מחלקת String הוארכה בג'אווה 1.4 כדי לספק שיטת matches
המבצעת תאמת דפוס regex. פנימית היא משתמשת במחלקות ה־Pattern
וה־Matcher
של ג'אווה כדי לבצע את העיבוד אך זאת ברור שזה מפחית את קווי הקוד. מחלקת Pattern מכילה גם את שיטת matches
שמקבלת regex ומחרוזת קלט כארגומנט ומחזירה תוצאת בוליאנית לאחר התאמתם. לכן הקוד הבא עובד בצורה תקינה להתאמת מחרוזת הקלט לביטוי רגיל בג'אווה.
String str = "bbb";
System.out.println("Using String matches method: "+str.matches(".bb"));
System.out.println("Using Pattern matches method: "+Pattern.matches(".bb", str));
בכך שהדרישה שלך היא רק לבדוק אם מחרוזת הקלט תואמת את התבנית, כדאי לחסוך זמן וקוד באמצעות שימוש בשיטת התאמת מחרוזת פשוטה. יש להשתמש במחלקות Pattern ו-Matches רק כאשר יש צורך לעבד את מחרוזת הקלט או יש צורך להשתמש בתבנית מחדש. שים לב שהתבנית שמוגדרת על ידי regex נפעלת על מחרוזת הקלט משמאל לימין ופעם אחת שתווית המקור בשימוש בהתאמה, הם לא יכולים להיות בשימוש חוזר. לדוג, regex "121" יתאים "31212142121" רק פעמיים כמו "_121____121".
ביטויים רגולריים ב-Java – סמלים שכיחים להתאמה
Regular Expression | Description | Example |
---|---|---|
. | Matches any single character | (“…”, “a%”) – true(“…”, “.a”) – true (“…”, “a”) – false |
^aaa | Matches aaa regex at the beginning of the line | (“^a.c.”, “abcd”) – true (“^a”, “ac”) – false |
aaa$ | Matches regex aaa at the end of the line | (“…cd$”, “abcd”) – true(“a$”, “a”) – true (“a$”, “aca”) – false |
[abc] | Can match any of the letter a, b or c. [] are known as character classes. | (“^[abc]d.”, “ad9”) – true(“[ab].d$”, “bad”) – true (“[ab]x”, “cx”) – false |
[abc][12] | Can match a, b or c followed by 1 or 2 | (“[ab][12].”, “a2#”) – true(“[ab]…[12]”, “acd2”) – true (“[ab][12]”, “c2”) – false |
[^abc] | When ^ is the first character in [], it negates the pattern, matches anything except a, b or c | (“[^ab][^12].”, “c3#”) – true(“[^ab]…[^12]”, “xcd3”) – true (“[^ab][^12]”, “c2”) – false |
[a-e1-8] | Matches ranges between a to e or 1 to 8 | (“[a-e1-3].”, “d#”) – true(“[a-e1-3]”, “2”) – true (“[a-e1-3]”, “f2”) – false |
xx | yy | Matches regex xx or yy |
מטא-תווים ב-Regex של Java
ישנם מטא-תווים מסוימים ב-Regex של Java, כמו קודים קצרים להתאמות דפוסים שכיחים.
Regular Expression | Description |
---|---|
\d | Any digits, short of [0-9] |
\D | Any non-digit, short for [^0-9] |
\s | Any whitespace character, short for [\t\n\x0B\f\r] |
\S | Any non-whitespace character, short for [^\s] |
\w | Any word character, short for [a-zA-Z_0-9] |
\W | Any non-word character, short for [^\w] |
\b | A word boundary |
\B | A non word boundary |
ישנם שני דרכים להשתמש במטא-תווים כתווים רגילים בביטויים רגולריים.
- לפני המטא-תווים, הקדימות לתווים עם סלש (/).
- שמור על המטא-תווים בתוך \Q (שמתחיל בציטוט) ו-\E (שמסיים אותו).
ביטוי רגולרי ב-Java – קוונטיפיירים
קוונטיפיירים ב-Java Regex מציינים את מספר הופעות התו להתאמה.
Regular Expression | Description |
---|---|
x? | x occurs once or not at all |
X* | X occurs zero or more times |
X+ | X occurs one or more times |
X{n} | X occurs exactly n times |
X{n,} | X occurs n or more times |
X{n,m} | X occurs at least n times but not more than m times |
קוונטיפיירים ב-Java Regex ניתפים לשימוש עם מחלקות תווים וקבוצות לכידה גם. לדוגמה, [abc]+ אומר – a, b או c – פעמים אחת או יותר. (abc)+ אומר קבוצת "abc" פעם אחת או יותר. נדבר עכשיו על קבוצת לכידה עכשיו.
ביטוי רגולרי ב-Java – קבוצות לכידה
קבוצות לכידה ביטוי רגולרי ב-Java משמשות לטיפול בתווים מרובים כיחידה אחת. ניתן ליצור קבוצה באמצעות ()
. החלק של מחרוזת הקלט שמתאים לקבוצת הלכידה מתווסף לזיכרון וניתן לקרוא אותו באמצעות התייחסות אחורית. ניתן להשתמש בשיטת matcher.groupCount
כדי לגלות את מספר הקבוצות לכידה בתבנית regex של Java. לדוגמה, ((a)(bc)) מכיל 3 קבוצות לכידה – ((a)(bc)), (a) ו- (bc). ניתן להשתמש ב-התייחסות אחורית בביטוי הרגולרי עם חזרה (\) ואז מספר הקבוצה שיש לקרוא. קבוצות לכידה והתייחסויות אחוריות יכולות להיות מבלבלות, אז בואו נבין זאת בעזרת דוגמה.
System.out.println(Pattern.matches("(\\w\\d)\\1", "a2a2")); //true
System.out.println(Pattern.matches("(\\w\\d)\\1", "a2b2")); //false
System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B2AB")); //true
System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B3AB")); //false
בדוגמה הראשונה, ב-runtime, הקבוצה הראשונה שמופעלת היא (\w\d) שמשווה ל-"a2" כאשר היא מתאימה למחרוזת הקלט "a2a2" ומורשת בזיכרון. לכן, \1 מתייחסת ל-"a2" ולכן מחזירה אמת. בשל אותו הסיבה, ההצהרה השנייה מדפיסה שקר. נסה להבין את התרחשות זו להצהרות 3 ו-4 בעצמך. 🙂 עכשיו נסתכל על כמה מתודות חשובות של מחלקות Pattern ו- Matcher.
- ניתן ליצור אובייקט Pattern עם דגלים. לדוגמה,
Pattern.CASE_INSENSITIVE
מאפשר התאמה לא תלויה באותיות רישיות. - מחלקת Pattern גם מספקת את המתודה
split(String)
שדומה למתודהsplit()
של מחלקת String. - מחלקת Pattern, באמצעות המתודה
toString()
, מחזירה מחרוזת ביטוי רגולרי ממנה התרגל תבנית זו. - למחלקות Matcher יש מתודות אינדקס
start()
ו-end()
שמציינות בדיוק איפה המתאימות נמצאות במחרוזת הקלט. - מחלקת Matcher גם מספקת מתודות לניהול מחרוזות, כמו
replaceAll(String replacement)
ו-replaceFirst(String replacement)
.
בוא נסתכל על אלו מתודות regex בתכנית דוגמה פשוטה ב-Java.
package com.journaldev.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExamples {
public static void main(String[] args) {
// בשימוש בתבנית עם דגלים
Pattern pattern = Pattern.compile("ab", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher("ABcabdAb");
// בשימוש במתודות find(), group(), start() ו- end() של Matcher
while (matcher.find()) {
System.out.println("Found the text \"" + matcher.group()
+ "\" starting at " + matcher.start()
+ " index and ending at index " + matcher.end());
}
// בשימוש במתודה split() של Pattern
pattern = Pattern.compile("\\W");
String[] words = pattern.split("one@two#three:four$five");
for (String s : words) {
System.out.println("Split using Pattern.split(): " + s);
}
// בשימוש במתודות replaceFirst() ו- replaceAll() של Matcher
pattern = Pattern.compile("1*2");
matcher = pattern.matcher("11234512678");
System.out.println("Using replaceAll: " + matcher.replaceAll("_"));
System.out.println("Using replaceFirst: " + matcher.replaceFirst("_"));
}
}
פלט של דוגמה זו של תכנית regex ב-Java הוא.
Found the text "AB" starting at 0 index and ending at index 2
Found the text "ab" starting at 3 index and ending at index 5
Found the text "Ab" starting at 6 index and ending at index 8
Split using Pattern.split(): one
Split using Pattern.split(): two
Split using Pattern.split(): three
Split using Pattern.split(): four
Split using Pattern.split(): five
Using replaceAll: _345_678
Using replaceFirst: _34512678
זהו כל הדברים על ביטויים רגולריים ב-Java. ביטויים רגולריים ב-Java נראים קשים בהתחלה, אך אם תעבוד עם הם לזמן מה, זה יהיה קל ללמוד ולהשתמש בהם.
ניתן לבדוק קוד מלא ודוגמאות נוספות של ביטויים רגולריים ב-מאגר הקוד שלנו ב-GitHub.
Source:
https://www.digitalocean.com/community/tutorials/regular-expression-in-java-regex-example