2012-03-18 124 views
3

我正在學習正則表達式,並認爲我已經開始掌握了。但後來......拆分字符串與正則表達式 w w *? w +?

我試圖分裂一個字符串,我需要幫助理解這樣一個簡單的事情:

String input = "abcde"; 
System.out.println("[a-z] " + Arrays.toString(input.split("[a-z]"))); 
System.out.println("\\w " + Arrays.toString(input.split("\\w"))); 
System.out.println("\\w*? " + Arrays.toString(input.split("\\w*?"))); 
System.out.println("\\w+? " + Arrays.toString(input.split("\\w+?"))); 

The output is 
[a-z] - [] 
\w - [] 
\w*? - [, a, b, c, d, e] 
\w+? - [] 

爲什麼沒有任何兩個第一線的任何字符分割字符串? 第三個表達式\ w * ?,(問號防止貪婪)按我的預期工作,在每個字符上分割字符串。星號,零個或多個匹配項返回一個空數組。

我已經試過內記事本+ +,並在節目中表達,它顯示了5場比賽,如:基本

Scanner ls = new Scanner(input); 
while(ls.hasNext()) 
    System.out.format("%s ", ls.findInLine("\\w"); 

Output is: a b c d e 

這真的讓我爲難,

+0

我不能相信你會被分配到Java的正則表達式作業,而不是使用不需要的語言\\ dd \\ oo \\ uu \\ bb \\ ll \\ ee \\ \\ bb \\ AA \\立方厘米\\ KK \\ SS \\ LL \\ AA \\ SS \\ HH \\ EE \\ SS !!什麼酷刑!另外你甚至沒有編譯時檢查正則表達式的語法,也沒有調試等等等等。Java對於這類工作並不是很方便。你應該用更加同情的語言來開發你的正則表達式,然後把最終結果傳給Java。 – tchrist 2012-03-18 19:04:47

+0

@tchrist你在想什麼語言? – Kennet 2012-03-19 08:29:32

+0

除了像sed和awk這樣的shell工具之外,Perl和Ruby還有第一類正則表達式,甚至Python也可以讓你跳過雙擊頁面。 Perl是唯一一個使用正則表達式調試器的人。 – tchrist 2012-03-19 13:22:35

回答

8

如果用正則表達式分割字符串,告訴哪裏應該切斷字符串。這必然會削減你與正則表達式匹配的東西。這意味着如果你在\w處分割,那麼每個字符都是一個分割點,它們之間的子串(全部爲空)將被返回。 Java會自動刪除尾隨的空字符串,如the documentation中所述。

這也解釋了爲什麼懶惰匹配\w*?會給你每個字符,因爲它會匹配任何字符(零寬度)之間(以及之前和之後)的每個位置。剩下的是字符串本身的字符。

讓我們來分析一下:

  1. [a-z]\w\w+?

    你的字符串是

    abcde 
    

    而且MATC HES如下:

    a b c d e 
    └─┘└─┘└─┘└─┘└─┘ 
    

    這讓您與子比賽之間,所有這一切都是空的。

    上述三個正則表達式在這方面表現相同,因爲它們都只會匹配單個字符。 \w+?會這樣做,因爲它缺少任何其他限制,可能會使+?嘗試匹配的不僅僅是最低限度(畢竟它很懶惰)。

  2. \w*?

    a b c d e 
    └┘ └┘ └┘ └┘ └┘ └┘ 
    

    在這種情況下比賽是人物之間,讓你用下面的字符串:

    "", "a", "b", "c", "d", "e", "" 
    

    的Java拋出後空單了,雖然。

+1

Java的'split'拋棄了尾部空字段,因爲它模仿了Perl的'split',這就是它的原因。在這兩種語言中,你可以通過在'-1'的'split'中添加另一個參數來抑制這種行爲。 – tchrist 2012-03-18 19:06:13

1

String.split切割串在圖案中的每個匹配:

通過此方法返回的數組中包含該字符串由另一個子匹配給定表達或終止終止的每個子在字符串的末尾。

因此,只要像[a-z]這樣的模式匹配,字符串就會在該匹配處被剪切。由於字符串中的每個字符都與該模式匹配,所以得到的數組是空的(刪除尾隨空字符串)。

這同樣適用於\w\w+?(一個或多個\w但儘可能少的重複)。那\w*?產生的結果是你期望的是由於*?量詞,因爲如果可能的話,它將匹配零重複,所以一個空字符串。在給定字符串中的每個位置都會找到一個空字符串。

+0

這也是有幫助的,謝謝! – Kennet 2012-03-18 18:44:20

2

我們將每個電話分解爲String#split(String)。從Java文檔中注意到,「方法的工作方式好像通過調用the two-argument split method與給定的表達式並且極限參數爲零。尾隨的空字符串因此不包括在結果數組中」。

"abcde".split("[a-z]"); // => [] 

這一個的每個字符(A,B,C,d,e)和結果匹配只有它們之間的空字符串,這被省略。

"abcde".split("\\w")); // => [] 

同樣,在字符串中的每個字符是一個字字符(\w),所以結果是空字符串,這被省略。

"abcde".split("\\w*?")); // => ["", "a", "b", "c", "d", "e"] 

在這種情況下,*表示「零個或多個前述項的」(\w),其七次匹配的空表達(一次在字符串的開頭然後一旦每個字符之間)。所以我們得到第一個空字符串然後是每個字符。

"abcde".split("\\w+?")); // => [] 

這裏+指「一個或多個前述項的」(\w),其整個輸入串相匹配,導致只有空字符串,其中省略。

input.split(regex, -1)再次嘗試這些示例,您應該看到所有空字符串。

+0

我也想接受你的答案,謝謝你的幫助! – Kennet 2012-03-18 18:43:06

+0

@Kennet:當然,請考慮提高你認爲有幫助的答案。 – maerics 2012-03-18 18:47:57

相關問題