RegEx 正規表示式是什麼?
事實上,正規表示式(Java 中的 RegEx)是一種在文字中搜尋字串的模式。在Java中,這種模式的初始表示總是一個字串,即String類別的物件。但是,並不是任何字串都可以編譯為正規表示式,只有那些遵循正規表示式編寫規則(語言規範中定義的語法)的字串才可以編譯為正規表示式。要編寫正規表示式,需要使用字母和數字字元以及元字元 - 在正規表示式語法中具有特殊含義的字元。例如:String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;
在 Java 中建立正規表示式
要在 Java 中建立 RegEx,您需要遵循兩個簡單的步驟:- 使用正規表示式語法將其寫為字串;
- 將此字串編譯為正規表示式;
Pattern
。為此,您需要呼叫類別中可用的兩個靜態方法之一compile
。第一個方法採用一個參數 - 正規表示式的字串文字,第二個 - 加上另一個參數,用於開啟將模板與文字進行比較的模式:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
可能的參數值清單flags
是在類別中定義的Pattern
,並且可以作為靜態類別變數提供給我們。例如:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//searching for matches with the pattern will be done case-insensitively.
本質上,該類別Pattern
是一個正規表示式建構函數。在底層,該方法compile
呼叫類別的私有建構函式Pattern
來建立編譯視圖。實現這種創建模板實例的方法的目的是將其創建為不可變物件。建立時,會執行正規表示式的語法檢查。如果該行中有錯誤,則會產生異常PatternSyntaxException
。
正規表示式語法
正規表示式語法基於符號的使用<([{\^-=$!|]})?*+.>
,符號可以與字母字元組合。根據他們的角色,他們可以分成幾組:
元字元 | 目的 |
---|---|
^ | 行首 |
$ | 行結束 |
\b | 字邊界 |
\B | 沒有字數限制 |
\A | 輸入開始 |
\G | 上一場比賽結束 |
\Z | 輸入結束 |
\z | 輸入結束 |
元字元 | 目的 |
---|---|
\d | 數字符號 |
\D | 非數字字符 |
\s | 空格字符 |
\S | 非空白字符 |
\w | 字母數字字元或底線 |
\W | 除字母、數字或下劃線之外的任何字符 |
。 | 任何字元 |
元字元 | 目的 |
---|---|
\t | 製表符 |
\n | 換行符 |
\r | 回車符 |
\F | 前往新頁面 |
\u0085 | 下一行字符 |
\u 2028 | 行分隔符 |
\u 2029 | 段落分隔符 |
元字元 | 目的 |
---|---|
[乙丙] | 上述任何一項(a、b 或 c) |
[^abc] | 列出的以外的任何其他內容(非 a、b、c) |
[a-zA-Z] | 範圍合併(拉丁字元 a 到 z 不區分大小寫) |
[廣告[mp]] | 字串聯(a 到 d 和 m 到 p) |
[az&&[def]] | 符號的交集(符號 d、e、f) |
[az&&[^bc]] | 減去字元(字元 a、dz) |
元字元 | 目的 |
---|---|
? | 一個或缺失 |
* | 零次或多次 |
+ | 一次或多次 |
{n} | n次 |
{n,} | n次或以上 |
{n,m} | 不少於n次且不多於m次 |
貪婪量詞模式
量詞的一個特殊功能是能夠以不同的模式使用它們:貪婪、超貪婪和惰性。超貪婪模式+
透過在量詞後面加上符號「 」開啟,惰性模式透過新增符號「 ?
」開啟。例如:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
使用此模板作為範例,讓我們嘗試了解量詞在不同模式下的工作方式。預設情況下,量詞以貪婪模式運行。這意味著它會在字串中查找最長的可能匹配。運行此程式碼的結果是:
public static void main(String[] args) {
String text = "Egor Alla Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
我們將得到以下輸出: Alla Alexa 給定模式「 」的搜尋演算法А.+а
按以下順序執行:
-
在給定的模式中,第一個字元是俄語字母字元
А
。Matcher
從位置零開始,將其與文字的每個字元進行匹配。在文本中的位置 0 處有一個符號Е
,因此Matcher
它會按順序遍歷文本中的字符,直到遇到與模式的匹配項。在我們的範例中,這是位置 5 處的符號。 -
找到與模式的第一個字元的匹配後,
Matcher
它會檢查與模式的第二個字元的匹配。在我們的例子中,這是符號“.
”,它代表任何字元。第六位是字母符號
л
。當然,它匹配“任何字元”模式。 -
Matcher
繼續檢查模式中的下一個字元。在我們的模板中,它是使用“.+
”量詞指定的。由於模式中「任意字元」的重複次數為一次或多次,因此Matcher
只要滿足「任意字元」條件,它就會依次從字串中取出下一個字元並檢查其是否符合模式,在我們的範例中-直到行尾(從文本的第7 號位置到第18 號位置)。事實上,
Matcher
它把整條線都抓到了最後——這就是它的「貪婪」體現的地方。 -
Matcher
到達文字末尾並完成對模式的“ ”部分的檢查後А.+
,Matcher 開始檢查模式的其餘部分 - 字母字元а
。由於正向的文字已經結束,因此檢查發生在反向,從最後一個字元開始: -
Matcher
「記住」模式「.+
」到達文字結尾時的重複次數,因此它將重複次數減少一併檢查文字的模式,直到找到匹配:
超貪婪量詞模式
在超貪婪模式下,匹配器的工作方式與貪婪模式機制類似。不同之處在於,當您將文字抓取到行尾時,不會向後搜尋。也就是說,超貪婪模式的前三個階段將與貪婪模式類似。捕獲整個字串後,匹配器會新增模式的其餘部分並將其與捕獲的字串進行比較。在我們的範例中,當使用模式「А.++а
」執行 main 方法時,將找不到匹配項。
惰性量詞模式
-
在此模式下,在初始階段,與貪婪模式一樣,將尋求與模式的第一個字元的匹配:
-
接下來,它會尋找與模式中的下一個字元(任何字元)的匹配項:
-
與貪婪模式不同,惰性模式會搜尋文字中的最短匹配,因此在找到與模式的第二個字元(由點指定並與文字中第 6 號位置的字元匹配)的匹配後,將檢查文字是否
Matcher
與模式的其餘部分匹配- “а
”字元。 -
由於未找到與文字中的模式相符的內容(文本中的第 7 位置有符號“ ”
л
),Matcher
因此在模式中添加另一個“任意字元”,因為它被指定為一次或多次,再次將圖案與第5 號到第8 號位置的文字進行比較: -
在我們的例子中,找到了匹配項,但尚未到達文本末尾。因此,從位置 9 開始,檢查首先使用類似的演算法搜尋模式的第一個字符,然後重複直到文字結尾。
main
當使用「А.+?а
」範本時,我們將得到以下結果: Alla Alexa 從我們的範例中可以看出,當對相同範本使用不同的量詞模式時,我們得到了不同的結果。因此,在搜尋時需要考慮到此特點,根據想要的結果選擇所需的模式。
正規表示式中的轉義字符
由於 Java 中的正規表示式(或更準確地說其初始表示形式)是使用字串文字指定的,因此有必要考慮與字串文字相關的 Java 規範的規則。特別是,\
Java 原始程式碼中字串文字中的反斜線字元「」被解釋為轉義字符,警告編譯器後面的字符是特殊字符,必須以特殊方式解釋。例如:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
因此,在描述正規表示式並使用「\
」字元(例如,對於元字元)的字串文字中,必須將其加倍,以便 Java 字節碼編譯器不會對其進行不同的解釋。例如:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
如果我們打算將特殊字符用作“常規”字符,則還應該使用雙反斜杠字符來轉義特殊字符。例如:
String regex = "How\\?"; // template for searching the string "How?"
Pattern 類別的方法
這類Pattern
還有其他處理正規表示式的方法: String pattern()
– 傳回建立物件的正規表示式的原始字串表示形式Pattern
:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)
– 讓您根據參數中傳遞的文字檢查在 regex 參數中傳遞的正規表示式input
。傳回: true – 如果文字與模式相符; 假——否則;例子:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla Alexander"));//false
int flags()
– 傳回flags
已建立時設定的範本參數值,若未設定此參數則傳回0。例子:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)
– 將作為參數傳遞的文字拆分為元素數組String
。此參數limit
決定在文字中搜尋的最大匹配數:
- 當–執行匹配
limit>0
搜尋;limit-1
- at
limit<0
– 搜尋文字中的所有符合項 - when
limit=0
– 搜尋文字中的所有符合項,同時丟棄陣列末端的空白行;
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("\\s");
String[] strings = pattern.split(text,2);
for (String s : strings) {
System.out.println(s);
}
System.out.println("---------");
String[] strings1 = pattern.split(text);
for (String s : strings1) {
System.out.println(s);
}
}
控制台輸出: Egor Alla Anna -------- Egor Alla Anna下面我們將考慮 另一種用於建立物件的類別方法Matcher
。
匹配器類別方法
Matcher
是一個類,從中建立物件來搜尋模式。Matcher
– 這是一個“搜尋引擎”,一個正規表示式的“引擎”。為了進行搜索,他需要獲得兩件事:搜索模式和搜索“地址”。為了創建對象,Matcher
類別中提供了以下方法Pattern
: рublic Matcher matcher(CharSequence input)
作為參數,該方法採用將在其中執行搜尋的字元序列。這些是實作介面的類別的物件CharSequence
。String
您不僅可以傳遞, ,還可以傳遞StringBuffer
, StringBuilder
, Segment
and作為參數CharBuffer
。搜尋模板是Pattern
呼叫該方法的類別物件matcher
。建立匹配器的範例:
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using the pattern "a*b"
現在,在「搜尋引擎」的幫助下,我們可以搜尋匹配項,找出匹配項在文字中的位置,並使用類別方法取代文字。該方法boolean find()
使用該模式在文字中搜尋下一個匹配項。使用此方法和循環運算符,您可以根據事件模型分析整個文字(當事件發生時執行必要的操作 - 在文字中尋找匹配項)。例如,使用此類別的方法,int start()
您int end()
可以確定文字中匹配的位置,並使用方法String replaceFirst(String replacement)
將String replaceAll(String replacement)
文字中的匹配替換為另一個替換文字。例子:
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found" + text.substring(start,end) + " с "+ start + " By " + (end-1) + "position");
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Olga"));
System.out.println(text);
}
程式輸出: 從 5 到 8 個位置找到了匹配的 Alla A 從 10 到 13 個位置找到了安娜匹配 Egor Ira Anna Egor Olga Olga Egor Alla Anna 從示例中可以清楚地看出,這些方法replaceFirst
創建了replaceAll
一個新對象String
- 一個字串,其中是來源文本,其中與模板的匹配項被替換為作為參數傳遞給方法的文本。此外,此方法replaceFirst
僅取代第一個匹配項,以及replaceAll
測試中的所有匹配項。原文保持不變。其他類別方法的使用Matcher
以及正規表示式的範例可以在本系列文章中找到。處理文字時最常見的正規表示式運算來自類Pattern
,並且Matcher
內建於String
. 這些是諸如split
、matches
、replaceFirst
、之類的方法replaceAll
。但事實上,「在幕後」他們使用Pattern
和Matcher
。因此,如果您需要在程式中替換文字或比較字串而不編寫不必要的程式碼,請使用String
. 如果您需要高級功能,請考慮類別Pattern
和Matcher
.
結論
正規表示式在 Java 程式中使用與規則定義的模式相符的字串進行描述。當程式碼執行時,Java 將此字串重新編譯為類別對象Pattern
,並使用該類別對像Matcher
在文字中尋找匹配項。正如我在一開始所說的,正規表示式經常被放在一邊以供以後使用,被認為是一個困難的話題。然而,如果您了解語法、元字元、轉義的基礎知識,並研究正規表示式的範例,您會發現它們比乍看之下要簡單得多。
GO TO FULL VERSION