java 正則式,正則表達式,多行匹配,不以某某開頭,不區分大小寫,2個單元的或操作

文章出處:http://topic.csdn.net/u/20080627/14/8a91b33a-f35c-4303-85b5-e0a8da462202.html

1 多行匹配 
2 不以某某開頭 ,比如不以www開頭 
3 不區分大小寫 
4 2個單元的或操作,比如  www ¦ 3w 都可以這種

火龍果回答:

1:多行匹配 

在默認的情況下 . 是不能匹配行結束符的(行結束符有 6 個,具體的可以看看 Pattern 的 API DOC) 
同樣,可以像不匹配大小寫匹配那樣使用編譯參數:Pattern.DOTALL 

如果還得區分大小寫的話,還得加上上面說到的 Pattern.CASE_INSENSITIVE 這個,舉個例子:

 

 

Java代碼 
  1. import java.util.regex.Matcher;  
  2. import java.util.regex.Pattern;public class Test {  
  3.   
  4.     public static void main(String[] args) {  
  5.         String str =   
  6.                 "<table>                /n" +  
  7.                 "  <tr>                 /n" +  
  8.                 "    <td>               /n" +  
  9.                 "       Hello World!    /n" +  
  10.                 "    </td>              /n" +  
  11.                 "  </tr>                /n" +  
  12.                 "</table>";  
  13.         String regex = "<td>(.+?)</td>";  
  14.         Pattern pattern = Pattern.compile(regex);  
  15.         Matcher matcher = pattern.matcher(str);  
  16.         while(matcher.find()) {  
  17.             System.out.println(matcher.group(1).trim());  
  18.         }          
  19.     }  
  20. }  

 

 

 

 

 

上面這個是不能從 str 抽取出東西的,因爲 td 的後面帶有換行符,我們只要更改一下: 

Pattern pattern = Pattern.compile(regex, Pattern.DOTALL); 

這樣就行了,如果 td 還得不區分大小寫的話,再改成:

Pattern pattern = Pattern.compile(regex, Pattern.DOTALL | Pattern.CASE_INSENSITIVE);

這樣的話,td 哪怕是大寫的這個表達式都能把 td 之間的字符區抽取出來。 

當然和 Pattern.CASE_INSENSITIVE 一樣,Pattern.DOTALL 也有內嵌標誌表達式,即 (?s) 
s 的意思表示 single-line 就是忽略換行符什麼的,只看成單行進行處理。 

這個表達式使用內嵌 (?s) 的話可以改爲:

String regex = "(?s)<td>(.+?)</td>";

如果還要不區分大小寫的話,再加上 i 標誌:
String regex 
= "(?s)(?i)<td>(.+?)</td>";

但這樣顯得很拖沓,可以把它們合併起來:
String regex 
= "(?is)<td>(.+?)</td>";    // 秩序無所謂

最後需要說明一下的是,我曾看到過由於不明白 DOTALL,爲了讓 . 匹配行結束符,直接把表達式寫成:

String regex = "<td>((.|//s)+?)</td>";

這樣做是極其危險的,由於選擇結構的匹配效率問題,這樣做在比較長的字符串時會造成堆棧溢出, 
使程序崩潰,如果使用 DOTALL 或者 (?s) 的話就不會出現這種情況。

2:不以某某開頭 ,比如不以www開頭 

Java代碼 
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.         String[] strs = {  
  5.                 "abc1232",  "wwwadsf",  
  6.                 "awwwfas",  "wwadfsf",  
  7.                 """ww"" ""www"  
  8.             };  
  9.         String regex = "(?:(?!^www).)*";  
  10.         for(String str : strs) {  
  11.             System.out.printf("%-7s %s%n", str, str.matches(regex));  
  12.         }  
  13.     }  
  14. }  

 

 

(?!X) 專業名稱爲 Negative Lookahead,表示字符間縫隙後面不允許出現的字符, 
即匹配字符間的縫隙,如果縫隙後的字符不是 X 的話,那這個縫隙就匹配成功。 

舉個例子,aab 和 aac,現有表達式 aa(?!b) 這時我們能匹配到的字符串是 aac, 
因爲 aa 的後面的縫隙之後不允許出現字符 b,因此只有 aac 進行了匹配。 

再來看個示例: 

Java代碼 
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         String str = "AQuickBrownFoxJumpsOverTheLazyDog";  
  4.         String[] strs = str.split("(?<!^)(?=[A-Z])");  
  5.         for(String s : strs) {  
  6.             System.out.println(s);  
  7.         }  
  8.     }  
  9. }  

 

 

 

根據大寫字母拆分字符串。當然了,這個使用字符串進行分析同樣也能進行拆分, 
但是使用正則表達式來拆的話更爲便捷直觀一些。 

在進行這種拆分時,由於在拆分後的字符數不能減少,因此只能使用零寬度的 
lookaround 功能進行匹配,lookaround 包括四個,即:

(?=X)  (?!X)  (?<=X)  (?<!X)

來看一下這個表達式:(? <!^)(?=[A-Z]) 

前面說到過 (?!) 表示縫隙後面不允許出現的東西,而 (? <!) 表示縫隙前不允許出現的東西。 
(?=) 表示縫隙後允許出現的東西,(? <=) 表示縫隙前允許出現的東西。 

這個表達式在拆分時,根據零寬度匹配縫隙進行拆分的,這個縫隙必須滿足以下條件: 

(? <!^) 表示縫隙不允許前不能是行開始,即縫隙不能出現在首字母的前面。 
(?=[A-Z]) 表示縫隙後面允許出現 A-Z 的大寫字母。 

這時這個表達式就匹配了下面帶有 ¦ 的縫隙:

A|Quick|Brown|Fox|Jumps|Over|The|Lazy|Dog
PS:不加 (
?<!^) 的話,會變成:
|A|Quick|Brown|Fox|Jumps|Over|The|Lazy|Dog

根據 split 的功能,正則表達式處理程序就根據上面的 ¦ 將字符串給拆分開來了。 


3,不區分大小寫 
不加任何限制的匹配是匹配分大小寫的,但是正則表達式中可以進行改變, 
有兩種方式:參數式和內嵌式。 

來看個示例:

 

Java代碼 
  1. import java.util.regex.Matcher;  
  2. import java.util.regex.Pattern;public class Test {  
  3.   
  4.     public static void main(String[] args) {          
  5.         String str = "Book";  
  6.         Pattern pattern = Pattern.compile("book");  
  7.         Matcher matcher = pattern.matcher(str);  
  8.         System.out.println(matcher.matches());  
  9.     }  
  10. }  

 

 

 

 

 

 

 

 

 

上面的這個表達式 book 是不能匹配字符串 Book 的,這時我們只要給定編譯時的參數就可以了: 

Pattern pattern = Pattern.compile("book", Pattern.CASE_INSENSITIVE); 

Pattern.CASE_INSENSITIVE 這是一個 int 類型的常量,值爲 2。表示表達式忽略大小寫進行區配。 

如果我們不採用 Pattern 和 Matcher 兩個類來匹配的話,只是使用 String 的 matches 方法的話, 
我們就不能指定表達式的編譯參數了,這時就需要採用內嵌標誌表達式了,與 Pattern.CASE_INSENSITIVE 
對應的內嵌標誌表達式是 (?i),它有四種形式: 
1,(?i) 
2,(?-i) 
3,(?i:X) 
4,(?-i:X) 
不帶有 - 的是開標誌,帶有 - 的是關標誌。 

把上面的代碼改成這樣:

Java代碼 
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {          
  4.         String str = "Book";  
  5.         String regex = "(?i)book";  
  6.         System.out.println(str.matches(regex));  
  7.     }  
  8. }  

 

 

 

我們就達到了同樣的效果,當然這樣並不是最好的,因爲字符串中只有 B 是大寫的, 
我們沒有必要把所有的字符都進行不區分大小寫匹配,我們可以在打開標誌,用 (?i) 的 
第二種形式馬上關掉它: 
    String regex = "(?i)b(?-i)ook"; 

這樣的話,只有 b 是區分大小寫了,而 (?-i) 後面的還是得區分大小寫匹配的。這樣寫 
可能看上去很不順眼,我們還能使用第 3 種形式直接指定某些字符是不區分大小寫的。 
    String regex = "(?i:b)ook"; 

這樣的表達式與上面的那個在語義上是相同的。就效率上肯定是優於一下子開,一下子關的。 

可見內嵌標誌表達式要比指定編譯參數的功能強大許多。 

使用建議:如果能確定某些字符的大小寫時,儘量使用已確定的字符,對於不確定的可以採用 
(?i:X) 的方式指定。因此打開不區分大小寫開關時,對匹配的性能是有一定影響的。 

思考一下:String regex = "(?i)b(?-i:oo)k"; 這個表達式的意思? 


另外:第 1 和第 4,我沒看明白需要了解什麼,請在下面的樓層中具體地說明一下。

4:2個單元的或操作 

¦ 稱爲多選結構,用於匹配 ¦ 之中的任何一個,拿你的例子來說明:

 

Java代碼 
  1. import java.util.regex.Matcher;  
  2. import java.util.regex.Pattern;public class Test {  
  3.   
  4.     public static void main(String[] args) {  
  5.         String str =   
  6.                 "<img src=/"http://www.google.com/1.gif/"/>/n" +  
  7.                 "<img src=/"http://3w.google.com/1.gif/"/>/n" +  
  8.                 "<img src=/"http://abc.baidu.com/1.gif/"/>";  
  9.         String regex = "<img//ssrc=/"http://(?:ww|3)w.google.com/1.gif/"/>";  
  10.         Pattern pattern = Pattern.compile(regex);  
  11.         Matcher matcher = pattern.matcher(str);  
  12.         while(matcher.find()) {  
  13.             System.out.println(matcher.group());  
  14.         }          
  15.     }  
  16. }  

 

 

 

 

 

 

 

注意到其中的 (?:ww ¦3) 在進行多選匹配時儘量找出多選中的規律,以減少多選的字符, 
www 和 3w 在最後一個字符可以共用,前面的不一樣。 

(?: ) 的意思表示組成一組,如果沒有 (?: ) 這樣的話,表達式就變成了:

String regex = "<img//ssrc=/"http://ww|3w.google.com/1.gif/"/>";

這樣的語義完全變掉了, ¦ 是在一組中進行選擇,由於上面的那個表達式中沒有組,就把整個表 
達式作爲了一組,使用 ¦ 的話,就進行了整個表達式的多選結構了。這個表達式的意思是: 
匹配 <img ssrc="http://ww 或者是 3w.google.com/1.gif"/>,這樣的結果並不是我們所要的。 

我們僅僅需要在 ww 和 3 之間進行選擇,這時只要把 ww 和 3 放在一組中進行多選擇就可以了, 
變成 (?:ww ¦3)。 

還有,在多選結構中儘量把出現頻率高的放在前面,這樣可以加快匹配速度。 

多選結構的效率在傳統型的引擎中是效率低下的,如果是單個字符的選擇,比如 a $ & 之中的一個, 
那就不要使用 (?:a ¦$ ¦&) 了,可以直接使用字符類 [a$&] 就可以了。

5:split分割字母和數字,簡單正則縫隙

 

Java代碼 
  1. public class Test01 {  
  2.     public static void main(String[] args) {  
  3.         String str = "one123";  
  4.         String regex = "(?<=one)(?=123)";  
  5.         String[] strs = str.split(regex);  
  6.         for(int i = 0; i < strs.length; i++) {  
  7.             System.out.printf("strs[%d] = %s%n", i, strs[i]);  
  8.         }  
  9.     }  
  10. }  

 

發佈了177 篇原創文章 · 獲贊 14 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章