首頁  >  文章  >  Java  >  java 正規表示式

java 正規表示式

伊谢尔伦
伊谢尔伦原創
2016-12-05 10:36:101200瀏覽

Java 提供了強大的正規表示式API,在java.util.regex 套件下。本教學介紹如何使用正規表示式API。

正規表示式

一個正規表示式是一個用於文字搜尋的文字模式。換句話說,在文本中搜尋出現的模式。例如,你可以用正規表示式搜尋網頁中的郵件地址或超連結。

正規表示式範例

下面是一個簡單的Java正規表示式的例子,用於在文本中搜尋http://

String text    =        
   "This is the text to be searched " +       
  "for occurrences of the http:// pattern.";String pattern = ".*http://.*";boolean matches = Pattern.matches(pattern, text);
System.out.println("matches = " + matches);

範例程式碼實際上沒有偵測找到的http:// 是否是一個合法超連結的一部分,如包含網域名稱和後綴(.com,.net 等等)。程式碼只是簡單的查找字串 http:// 是否出現。

Java6 中關於正規表示式的API

本教學介紹了Java6 中關於正規表示式的API。

Pattern (java.util.regex.Pattern)

類別java.util.regex.Pattern 簡稱Pattern, 是Java正規表示式API中的主要入口,無論何時,需要使用正規表示式,從Pattern 類別開始

Pattern.matches()

檢查一個正規表示式的模式是否符合一段文字的最直接方法是呼叫靜態方法Pattern.matches(),範例如下:

String text    =        
  "This is the text to be searched " +        
  "for occurrences of the pattern.";String pattern = ".*is.*";boolean matches = Pattern.matches(pattern, text);
System.out.println("matches = " + matches);

上面程式碼在單字變數變數中找出「istext ” 是否出現,允許”is” 前後包含0或多個字元(由.* 指定)

Pattern.matches() 方法適用於檢查一個模式在一個文本中出現一次的情況,或適用於Pattern類的默認設定.

如果需要匹配多次出現,甚至輸出不同的匹配文本,或者只是需要非預設設定。需要透過Pattern.compile() 方法得到一個Pattern 實例。

Pattern.compile()

如果需要符合一個正規表示式在文字中多次出現,則需要透過Pattern.compile() 方法建立一個Pattern物件。範例如下

String text    =        
"This is the text to be searched " +        
"for occurrences of the http:// pattern.";
String patternString = ".*http://.*";
Pattern pattern = Pattern.compile(patternString);

可以在Compile 方法中,指定一個特殊標誌:

Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);

Pattern 類別包含多個標誌(int 類型),這些標誌可以控制Pattern 匹配模式的方式。上面程式碼中的標誌使模式匹配是忽略大小寫

Pattern.matcher()

一旦獲得了Pattern對象,接著可以獲得Matcher對象。 Matcher 範例用於匹配文字中的模式.範例如下

Matcher matcher = pattern.matcher(text);

Matcher類別有一個matches()方法,可以檢查文字是否符合模式。以下是關於Matcher的一個完整例子

String text    =        
"This is the text to be searched " +        
"for occurrences of the http:// pattern.";
String patternString = ".*http://.*";
Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(text);boolean matches = matcher.matches();
System.out.println("matches = " + matches);

Pattern.split()

Pattern 類別的 split()方法,可以用正規表示式作為分隔符,將文字分割為String類型的陣列。例:

String text = "A sep Text sep With sep Many sep Separators";String patternString = "sep";
Pattern pattern = Pattern.compile(patternString);String[] split = pattern.split(text);
System.out.println("split.length = " + split.length);for(String element : split){
    System.out.println("element = " + element);
}

上例中把text 文字分割成一個包含5個字串的陣列。

Pattern.pattern()

Pattern 類別的 pattern 傳回用於建立Pattern 物件的正規表示式,範例:

String patternString = "sep";Pattern pattern = Pattern.compile(patternString);String pattern2 = pattern.pattern();

上面程式碼中 pattern2 值為sep ,與patternString 變數相同。

Matcher (java.util.regex.Matcher)

java.util.regex.Matcher 類別用於匹配一段文字中多次出現一個正規表示式,Matcher 也適用於多文本中匹配同一個正規表示式。

Matcher 有很多有用的方法,詳細請參考官方JavaDoc。這裡只介紹核心方法。

以下程式碼示範如何使用Matcher

String text    =        
"This is the text to be searched " +        
"for occurrences of the http:// pattern.";
String patternString = ".*http://.*";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
boolean matches = matcher.matches();

先建立一個Pattern,然後得到Matcher ,呼叫matches() 方法,傳回true 表示模式匹配,回傳false表示不符。

可以用Matcher 做更多的事。

建立Matcher

透過Pattern 的matcher() 方法建立一個Matcher。

String text    =        
"This is the text to be searched " +        
"for occurrences of the http:// pattern.";
String patternString = ".*http://.*";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);

matches()

Matcher 類別的 matches() 方法用於在文本中匹配正則表達式

boolean matches = matcher.matches();

如果文本匹配正則表達式,matches() 方法返回true。否則回傳false。

matches() 方法不能用來找出正規表示式多次出現。如果需要,請使用find(), start() 和 end() 方法。

lookingAt()

lookingAt() 與matches() 方法類似,最大的不同是,lookingAt()方法對文本的開頭匹配正則表達式;而

matches() 對整個文本匹配正則表達式。換句話說,如果正規表示式符合文字開頭而不符合整個文字,lookingAt() 回傳true,而matches() 傳回false。 範例:

String text    =        
"This is the text to be searched " +        
"for occurrences of the http:// pattern.";
String patternString = "This is the";
Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(text);
System.out.println("lookingAt = " + matcher.lookingAt());
System.out.println("matches   = " + matcher.matches());

上面的範例分別對文字開頭和整個文字符合正規表示式 “this is the”. 符合文字開頭的方法(lookingAt()) 傳回true。

對整個文本匹配正則表達式的方法 (matches()) 返回false,因為 整個文本包含多餘的字符,而 正則表達式要求文本精確匹配”this is the”,前後又不能有額外字符。

find() + start() + end()

find() 方法用於在文本中找到出現的正則表達式,文本是創建Matcher時,透過 Pattern.matcher(text) 方法傳入的。如果在文字中多次匹配,find() 方法會傳回第一個,之後每次呼叫 find() 都會傳回下一個。

start() 和 end() 傳回每次符合的字串在整個文字中的開始和結束位置。實際上, end() 回傳的是字串末尾的後一位,這樣,可以在把 start() 和 end() 的回傳值直接用在String.substring() 裡。

String text    =        
"This is the text which is to be searched " +        
"for occurrences of the word 'is'.";
String patternString = "is";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
int count = 0;while(matcher.find()) {
    count++;
    System.out.println("found: " + count + " : "  + matcher.start() + " - " + matcher.end());
    }

这个例子在文本中找到模式 “is” 4次,输出如下:

found: 1 : 2 - 4
 found: 2 : 5 - 7
 found: 3 : 23 - 25
 found: 4 : 70 - 72

reset()

reset() 方法会重置Matcher 内部的 匹配状态。当find() 方法开始匹配时,Matcher 内部会记录截至当前查找的距离。调用 reset() 会重新从文本开头查找。

也可以调用 reset(CharSequence) 方法. 这个方法重置Matcher,同时把一个新的字符串作为参数传入,用于代替创建 Matcher 的原始字符串。

group()

假设想在一个文本中查找URL链接,并且想把找到的链接提取出来。当然可以通过 start()和 end()方法完成。但是用group()方法更容易些。

分组在正则表达式中用括号表示,例如:

(John)

此正则表达式匹配John, 括号不属于要匹配的文本。括号定义了一个分组。当正则表达式匹配到文本后,可以访问分组内的部分。

使用group(int groupNo) 方法访问一个分组。一个正则表达式可以有多个分组。每个分组由一对括号标记。想要访问正则表达式中某分组匹配的文本,可以把分组编号传入 group(int groupNo)方法。

group(0) 表示整个正则表达式,要获得一个有括号标记的分组,分组编号应该从1开始计算。

String text    =  
"John writes about this, and John writes about that," +                        
" and John writes about everything. "  ;
String patternString1 = "(John)";
Pattern pattern = Pattern.compile(patternString1);
Matcher matcher = pattern.matcher(text);while(matcher.find()) {
    System.out.println("found: " + matcher.group(1));
    }

以上代码在文本中搜索单词John.从每个匹配文本中,提取分组1,就是由括号标记的部分。输出如下

found: John
 found: John 
 found: John

多分组

上面提到,一个正则表达式可以有多个分组,例如:

(John) (.+?)

这个表达式匹配文本”John” 后跟一个空格,然后跟1个或多个字符,最后跟一个空格。你可能看不到最后的空格。

这个表达式包括一些字符有特别意义。字符 点 . 表示任意字符。 字符 + 表示出现一个或多个,和. 在一起表示 任何字符,出现一次或多次。字符? 表示 匹配尽可能短的文本。

完整代码如下

String text    =          
"John writes about this, and John Doe writes about that," +                  
" and John Wayne writes about everything."
        ;
        String patternString1 = "(John) (.+?) ";
        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);
        while(matcher.find()) {
                 System.out.println("found: " + matcher.group(1) +                      
                  " "       + matcher.group(2));
                  }

注意代码中引用分组的方式。代码输出如下

found: John writes 
found: John Doe 
found: John Wayne

嵌套分组

在正则表达式中分组可以嵌套分组,例如

((John) (.+?))

这是之前的例子,现在放在一个大分组里.(表达式末尾有一个空格)。

当遇到嵌套分组时, 分组编号是由左括号的顺序确定的。上例中,分组1 是那个大分组。分组2 是包括John的分组,分组3 是包括 .+? 的分组。当需要通过groups(int groupNo) 引用分组时,了解这些非常重要。

以下代码演示如何使用嵌套分组

String text    =          
"John writes about this, and John Doe writes about that," +                  
" and John Wayne writes about everything."
        ;
        String patternString1 = "((John) (.+?)) ";
        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);
        while(matcher.find()) {
              System.out.println("found:   ");
              }

输出如下

found: 
 found: 
 found:

replaceAll() + replaceFirst()

replaceAll() 和 replaceFirst() 方法可以用于替换Matcher搜索字符串中的一部分。replaceAll() 方法替换全部匹配的正则表达式,replaceFirst() 只替换第一个匹配的。

在处理之前,Matcher 会先重置。所以这里的匹配表达式从文本开头开始计算。

示例如下

String text    =          
"John writes about this, and John Doe writes about that," +                  
" and John Wayne writes about everything."
        ;
        String patternString1 = "((John) (.+?)) ";
        Pattern pattern = Pattern.compile(patternString1);
        Matcher matcher = pattern.matcher(text);
        String replaceAll = matcher.replaceAll("Joe Blocks ");
        System.out.println("replaceAll   = " + replaceAll);
        String replaceFirst = matcher.replaceFirst("Joe Blocks ");
        System.out.println("replaceFirst = " + replaceFirst);

输出如下

replaceAll = Joe Blocks about this, and Joe Blocks writes about that,and Joe Blocks writes about everything.
replaceFirst = Joe Blocks about this, and John Doe writes about that,and John Wayne writes about everything.

输出中的换行和缩进是为了可读而增加的。

注意第1个字符串中所有出现 John 后跟一个单词 的地方,都被替换为 Joe Blocks 。第2个字符串中,只有第一个出现的被替换。

appendReplacement() + appendTail()

appendReplacement() 和 appendTail() 方法用于替换输入文本中的字符串短语,同时把替换后的字符串附加到一个 StringBuffer 中。

当find() 方法找到一个匹配项时,可以调用 appendReplacement() 方法,这会导致输入字符串被增加到StringBuffer 中,而且匹配文本被替换。 从上一个匹配文本结尾处开始,直到本次匹配文本会被拷贝。

appendReplacement() 会记录拷贝StringBuffer 中的内容,可以持续调用find(),直到没有匹配项。

直到最后一个匹配项目,输入文本中剩余一部分没有拷贝到 StringBuffer. 这部分文本是从最后一个匹配项结尾,到文本末尾部分。通过调用 appendTail() 方法,可以把这部分内容拷贝到 StringBuffer 中.

String text    =          
"John writes about this, and John Doe writes about that," +                  
" and John Wayne writes about everything."
        ;
        String patternString1 = "((John) (.+?)) ";
        Pattern      pattern      = Pattern.compile(patternString1);
        Matcher      matcher      = pattern.matcher(text);
        StringBuffer stringBuffer = new StringBuffer();
        while(matcher.find()){
              matcher.appendReplacement(stringBuffer, "Joe Blocks ");
              System.out.println(stringBuffer.toString());
              }
matcher.appendTail(stringBuffer);
System.out.println(stringBuffer.toString());

注意我们在while循环中调用appendReplacement() 方法。在循环完毕后调用appendTail()。 代码输出如下:

Joe Blocks
 Joe Blocks about this, and Joe Blocks
 Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
 Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
 writes about everything.

Java 正则表达式语法

为了更有效的使用正则表达式,需要了解正则表达式语法。正则表达式语法很复杂,可以写出非常高级的表达式。只有通过大量的练习才能掌握这些语法规则。

Java 正则表达式语法

为了更有效的使用正则表达式,需要了解正则表达式语法。正则表达式语法很复杂,可以写出非常高级的表达式。只有通过大量的练习才能掌握这些语法规则。

本篇文字,我们将通过例子了解正则表达式语法的基础部分。介绍重点将会放在为了使用正则表达式所需要了解的核心概念,不会涉及过多的细节。详细解释,参见 Java DOC 中的 Pattern 类.

基本语法

在介紹進階功能前,我們先快速瀏覽下正規表示式的基本語法。

字元

是正規表示式中最常使用的一個表達式,作用是簡單的符合一個確定的字元。例如:

John

這個簡單的表達式將會在一個輸入文字中符合John文字。

可以在表達式中使用任意英文字元。也可以使用字元對於的8進制,16進位或unicode編碼表示。例如:

101x41u0041

以上3個表達式 都表示大寫字元A。第一個是8進位編碼(101),第2個是16進位編碼(41),第3個是unicode編碼(0041).

字元分類

字元分類是一種結構,可以針對多個字元匹配而不只是一個字元。換句話說,一個字符分類匹配輸入文字中的一個字符,對應字符分類中多個允許字符。例如,你想要匹配字元 a,b 或c,表達式如下:

[abc]

用一對方括號[] 表示字元分類。方括號本身並不是想要匹配的一部分。

可以用字符分類完成很多事。例如想要匹配單字John,首字母可以為大寫和小寫J.

[Jj]ohn

字符分類[Jj] 匹配J或j,剩餘的ohn 會準確匹配字符ohn.

預定義字符分類

正規表示式中有一些預先定義的字元分類可以使用。例如, d 表示任意數字, s 表示任意空白字元,w 表示任意單字字元。

預定義字符分類不需要括在方括號裡,當然也可以組合使用

d[ds]

第1個匹配任意數字,第2個匹配任意數字或空白符。

完整的預定義字元分類列表,在本文最後列出。

邊界匹配

正規表示式支援匹配邊界,例如單字邊界,文字的開頭或末尾。例如,w 匹配一個單詞,^匹配行首,$ 匹配行尾。

^This is a single line$

上面的表達式匹配一行文本,只有文本 This is a single line。注意其中的行首和行尾標誌,表示不能有任何文字在文本的前面後後面,只能是行首和行尾。

完整的匹配邊界列表,在本文最後列出。

量詞匹配

量詞可以匹配一個表達式多次出現。例如下列表達式匹配字母A 出現0次或多次。

A* 
量詞 * 表示0次或多次。 + 表示1次或多次。 ? 表示0次或1次。還有一些其他量詞,請參考本文後面的列表。

量詞配對分為 飢餓模式,貪婪模式,獨佔模式。飢餓模式 盡可能匹配少的文字。貪婪模式匹配盡可能多的文字。獨佔模式匹配盡可能多的文本,甚至導致剩餘表達式匹配失敗。

以下示範飢餓模式,貪婪模式,獨佔模式差異。假設以下文字:

John went for a walk, and John fell down, and John hurt his knee. 
飢餓模式下表達式:

John.*?

這個表達式匹配John 後跟0個或多個字元。 . 表示任意字元。 * 表示0或多次。 ? 跟在 * 後面,表示 * 採取飢餓模式。

飢餓模式下,量詞只會匹配盡可能少的字符,即0個字符。上例中的表達式將會符合單字John,在輸入文字中出現3次。

如果改為貪婪模式,表達式如下:

John.*

貪婪模式下,量詞會匹配盡可能多的字符。現在表達式會匹配第一個出現的John,以及在貪婪模式下 匹配剩餘的所有字元。這樣,只有一個匹配項。

最後,我們改為獨佔模式:

John.*+hurt

*後跟+ 表示獨佔模式量詞。

這個表達式在輸入文字中沒有匹配項,儘管文本中包括 John 和 hurt. 為什麼會這樣? 因為 .*+ 是獨佔模式。與貪婪模式下,盡可能多的匹配文本,以使整個表達式匹配不同。獨佔模式會盡可能的多的匹配,但不考慮表達式剩餘部分是否能匹配上。

.*+ 將會匹配第一個John之後的所有字符,這會導致表達式中剩餘的 hurt 沒有匹配項。如果改為貪婪模式,會有一個匹配項。表達式如下:

John.*hurt

邏輯運算子

正規表示式支援少量的邏輯運算(與,或,非)。

與操作是預設的,表達式 John ,意味著J 與 o與h與n。

或操作需要顯示指定,以 | 表示。例如表達式 John|hurt 意味著John 或 hurt 。

字元

java 正規表示式

java 正規表示式

字元分類

java 正規表示式

java 正規表示式

量詞

java 正規表示式


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn