2008-12-25 27 views
7

我有一個包含幾行類似於文件:正則表達式來提取標籤 - 值對在Java中

Name: Peter 
Address: St. Serrano número 12, España 
Country: Spain 

我需要使用正則表達式來提取地址,考慮到它可以包含點,特殊字符(ñ,ç),áéíóú...

當前的代碼工作,但它看起來相當醜陋:。

Pattern p = Pattern.compile("^(.+?)Address: ([a-zA-Z0-9ñÑçÇáéíóú., ]+)(.+?)$", 
          Pattern.MULTILINE | Pattern.DOTALL); 
Matcher m = p.matcher(content); 
if (m.matches()) { ... } 

編輯:地址字段也可以劃分成多行

Name: Peter 
Address: St. Serrano número 12, 
Madrid 
España 
Country: Spain 

編輯:我不能使用Properties對象或YAML的解析器,因爲該文件包含其他種類的信息也是如此。

回答

6

我不知道Java的正則表達式對象很好,但像這種格局將做到這一點:

^Address:\s*((?:(?!^\w+:).)+)$ 

假設多和DOTALL模式上。

這將匹配任何以Address開頭的行,後面跟着任何東西,直到換行符和一個單詞後跟一個冒號。

如果你知道下一個字段必須是「國家」,可以簡化這個一點點:

^Address:\s*((?:(?!^Country:).)+)$ 

的訣竅是在重複組在先行斷言。 '(?!國家:)。'將匹配除字符串'Country:'之外的所有內容,因此我們只需將它放在非捕獲圓括號(?:...)中並用+對其進行量化,然後將所有這些組合在正常捕獲圓括號中。

0

不是Java人,但不會"Address: (.*)$"工作?

編輯:沒有Pattern.MULTILINE | Pattern.DOTALL選項只能在該行上匹配。

0

它是否可以包含換行符?如果它不能包含換行,不需要使用多修改,並且可以做,而不是

Pattern p = Pattern.compile("^Address: (.*)$"); 

如果可以,我能想到的一個替代方案是

Pattern p = Pattern.compile("Address: (.*)\nCountry", Pattern.MULTILINE); 

沒有DOTALL ,點不會匹配換行符,因此您可以在正則表達式中明確指定它,從而允許您執行所詢問的操作。

3

你可能想看看Properties類而不是正則表達式。它提供了管理純文本或XML文件以表示鍵值對的方法。

所以,你可以在你的示例文件讀取,然後得到像這樣加載到一個Properties對象後的值:

Properties properties = new Properties(); 
properties.load(/* InputStream of your file */); 

Assert.assertEquals("Peter", properties.getProperty("Name")); 
Assert.assertEquals("St. Serrano número 12, España", properties.getProperty("Address")); 
Assert.assertEquals("Spain", properties.getProperty("Country")); 
+0

爲什麼使用Apache Commons Assert而不是Java斷言? – cletus 2008-12-25 21:10:33

0

你一定要看看YAML

你可以試試JYaml

最好的是它有多種語言的實現。

ps我已經嘗試了YAML::XS中的示例文本,它完美地工作。

1

我並不是說要成爲一個泥土中的棍子,但是你必須使用正則表達式嗎?爲什麼不饒你未來的自己(或他人)的頭痛和做:

String line = reader.readLine(); 
while(line != null) 
{ 
    line = line.trim(); 
    if(line.startsWith("Address: ")) 
    { 
     return line.substr("Address: ".length()).trim(); 
    } 
    line = reader.readLine(); 
} 
return null; 

當然,這可以參數化的位以及投入的方法。

否則,我會第二個屬性或JYaml的建議。

3

假設「content」是一個包含文件內容的字符串,那麼您的主要問題是您正在使用matches(),您應該使用find()

Pattern p = Pattern.compile("^Address:\\s*(.*)$", Pattern.MULTILINE); 
Matcher m = p.matcher(content); 
if (m.find()) 
{ 
    ... 
} 

在關於MULTLINE和DOTALL模式的其他答案中似乎存在一些混淆。 MULTILINE是什麼讓^$定位符分別匹配邏輯行的開始和結束。 DOTALL讓點(句號,句號,任何)與\n(換行符)和\r(回車)等行分隔符相匹配。這個正則表達式必須使用MULTILINE模式和一定不能使用DOTALL模式。

+0

謝謝。如果地址是多行字段呢?是否有可能捕獲它而不需要依賴下一個字段名稱? – 2008-12-26 16:25:00

+0

如果地址字段位於輸入末尾,Nick的正則表達式將匹配。你是這個意思嗎? – 2008-12-27 01:58:51