2011-10-30 50 views
0

我正在計算一串數字中的0的數量。不僅僅是字符0,而是數字零。例如我想算0,0.0,0.000等的號碼將被用空格隔開,例如:正則表達式幫助只計算字符串中的零

1.0 5.0 1 5.4 12 0.1 14.2675 0.0 0.00005 

字符串中的一個簡單的搜索" 0"幾乎沒有工作(我必須先插入一個領先的空間這個工作的字符串 - 如果第一個數字是零)。然而,它不適用於​​3210等數字。 0.1,0.02等我想我需要檢查0,看看是否有一個小數點,然後非零數字,但我不知道該怎麼做。喜歡的東西:

" 0*|(0\\.(?!\\[1-9\\]))"

任何人有任何想法如何,我可能做到這一點?最好使用正則表達式。或者如果它更容易,我很樂意計算非零元素的數量。謝謝。

注意:我在Java中使用split來執行此操作(使用正則表達式拆分字符串,然後使用.length()進行計數)。

+0

可能不是一個偉大的正則表達式整體應用程序,但你試過「(^ | \\ s)([0。] +)(\\ s | $)」嗎?只有在沒有指數的情況下才能真正適用於格式良好的數字。如果連續有兩個零,我不認爲'split'會給你正確的答案。 – msandiford

回答

3

如何:

(?<=^|\s)[0.]+(?=\s|$) 

說明:

(?<=^|\s) # Assert position after a space or the start of the string 
[0.]+  # Match one or more zeroes/decimal points 
(?=\s|$) # Assert position before a space or the end of the string 

記得在Java字符串的反斜槓。

+1

... ... ... ........ < - 4零那裏 - 最好不要使用正則表達式 –

+1

當然可以。如果輸入可能與此格式不正確,則該正則表達式太簡單。然後使用' - ?0 +(?:\。0 +)?'而不是'[0。] +'。 –

+0

很抱歉,你能解釋一下你在最後一條評論中的含義嗎? Antti提到什麼情況? – MadScone

2

你應該用空格代替分裂,每個片段使用Double.parseDouble(),那麼如果它確實是一個雙,它比0

String[] parts = numbers.split("\\s+"); 
int numZeros = 0; 
for (String s: parts) { 
    try { 
     if (Double.parseDouble(s) == 0) { 
      numZeros ++; 
     } 
    } 
    catch (Exception e) { 
    } 
} 

沒有爲正則表達式不容易解決呢。最容易的想法是使用\ b邊界運算符,但它失敗了。另外,Double.parseDouble意味着像-0這樣的東西也被支持。

1

split()不是解決這個問題的方法,雖然它可以是部分的解決方案,正如Antti的答案所展示的。你會發現它更容易在一個循環匹配find()零值數和計數的比賽中,像這樣:

String s = "1.0 5.0 1 5.4 12 0.1 14.2675 0.0 0.00005 0. .0 0000 -0.0"; 

Pattern p = Pattern.compile("(?<!\\S)-?(?:0+(?:\\.?0*)|\\.0+)(?!\\S)"); 
Matcher m = p.matcher(s); 
int n = 0; 

while (m.find()) { 
    System.out.printf("%n%s ", m.group()); 
    n++; 
} 
System.out.printf("%n%n%d zeroes total%n", n); 

輸出:

0.0 
0. 
.0 
0000 
-0.0 

5 zeroes total 

這是如何添意味着你在他的回答中也使用正則表達式(我認爲)。打破正則表達式,我們有:

  • (?<!\\S)是匹配,這不是一個非空白字符前面的位置的負回顧後。這相當於Tim的積極向後看,(?<=^|\s),它明確地匹配字符串的開頭或右空白字符後面。

  • -?(?:0+(?:\\.?0*)|\\.0+)匹配一個可選的負號,後面跟着至少一個零和至多一個小數點。

  • (?!\\S)相當於(?=\s|$) - 它恰好在空白字符之前或在字符串的末尾匹配。

lookbehead和lookahead確保您始終匹配整個標記,就像您在分割空白時一樣。如果沒有這些,它也會匹配零作爲非零標記的一部分,如1230.0456


編輯(在響應評論):我主要反對使用split()是,它是不必要的令人費解。你正在創建一個包含你不關心的字符串的所有部分的字符串數組,然後根據數組的長度做一些數學運算以獲得你想要的信息。當然,這只是一行代碼,但它在溝通其意圖方面做得很差。任何不熟悉這個成語的人都會很難明白它的作用。

然後是尾隨空令牌問題:如果您對我修改過的示例字符串使用分割技術,則會得到4而不是5。這是因爲字符串的最後一個塊與分割正則表達式匹配,這意味着最後的標記應該是一個空字符串。但Java(在Perl的領導下)默認情況下默默地刪除尾隨的空令牌。您可以通過傳遞一個負整數作爲第二個參數來覆蓋該行爲,但是如果您忘記這麼做?這是一個非常容易犯的錯誤,並且可能很難排除故障。

至於性能,兩種方法在速度上幾乎相同(我不知道他們使用的內存)。使用合理大小的文本時,這不太可能會成爲問題。

+0

感謝您的回覆。爲什麼這個更適合使用'split'你介意我問嗎?我可以在一行'numberString.split((?<=^| \ s)[0。] +(?= \ s | $))。length - 1'中計算零,除了正則表達式本身,對我來說相當直接。您的解決方案是否有一些性能(或其他)優勢? – MadScone

+1

@MadScone:請參閱我的編輯回答我的回覆。 –