2010-08-10 59 views
15

我目前正在嘗試學習如何使用正則表達式,所以請忍受我的簡單問題。例如,假設我有一個包含了一堆用換行分隔鏈接輸入文件:正則表達式在Java中:如何處理新行

www.foo.com/Archives/monkeys.htm猴子的網站
說明。

www.foo.com/Archives/pigs.txt
豬的網站的描述。

www.foo.com/Archives/kitty.txt
Kitty的網站的描述。

www.foo.com/Archives/apple.htm
Apple網站的描述。

如果我想獲得一個網站,它的描述一起,這個正則表達式似乎在測試工具的工作:.*www.*\\s.*Pig.*

然而,當我嘗試我的代碼中運行它,它似乎不工作。這個表達是否正確?我試圖用「\ n」替換「\ s」,它似乎仍然不起作用。

回答

0

工作對我來說:

import java.util.regex.Pattern; 
import java.util.regex.Matcher; 
public class Foo { 
    public static void main(String args[]) { 
    Pattern p = Pattern.compile(".*www.*\\s.*Pig.*"); 
    String s = "www.foo.com/Archives/monkeys.htm\n" 
      + "Description of Monkey's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/pigs.txt\n" 
      + "Description of Pig's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/kitty.txt\n" 
      + "Description of Kitty's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/apple.htm\n" 
      + "Description of Apple's website.\n"; 
    Matcher m = p.matcher(s); 
    if (m.find()) { 
     System.out.println(m.group()); 
    } else { 
     System.out.println("ERR: no match"); 
    } 
    } 
} 

也許問題出在你使用的模式和Matcher對象的方式?

+1

這隻適用於行總是使用\ n格式化,如unix – Gary 2010-08-10 05:21:25

32

這些行在您的文件中可能會被\r\n分開。 \r(回車)和\n(換行符)都被認爲是Java正則表達式中的分隔符字符,並且.元字符與它們中的任何一個都不匹配。 \s將與這些字符匹配,因此它會消耗\r,但這會使.*\n相匹配,即失敗。您的測試儀可能只使用\n來分隔線,這些線被\s消耗。

如果我是對的,將\s更改爲\s+[\r\n]+應該可以使其正常工作。在這種情況下,這可能只是您需要做的所有事情,但有時您必須恰好匹配一個分隔線,或者至少跟蹤您匹配的人數。在這種情況下,您需要一個正則表達式,它與三種最常見的行分隔符類型中的任意一種匹配:\r\n(Windows/DOS),\n(Unix/Linus/OSX)和\r(較舊的Mac)。任何一項都將做到:

\r\n|[\r\n] 

\r\n|\n|\r 

更新:從Java 8中,我們有另一種選擇,\R。它匹配任何行分隔符,不僅包括\r\n,還包括Unicode standard定義的其他幾個分隔符。這是相同的:

\r\n|[\n\x0B\x0C\r\u0085\u2028\u2029] 

這裏是如何使用它:

(?im)^.*www.*\R.*Pig.*$ 

i選項使得它不區分大小寫,以及m把它在多模式,允許^$匹配在線邊界。

0

這個版本匹配新行可能是Windows(\ r \ n)的或Unix(\ n)的

Pattern p = Pattern.compile("(www.*)((\r\n)|(\n))(.*Pig.*)"); 
String s = "www.foo.com/Archives/monkeys.htm\n" 
      + "Description of Monkey's website.\n" 
      + "\r\n" 
      + "www.foo.com/Archives/pigs.txt\r\n" 
      + "Description of Pig's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/kitty.txt\n" 
      + "Description of Kitty's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/apple.htm\n" 
      + "Description of Apple's website.\n"; 
Matcher m = p.matcher(s); 
if (m.find()) { 
    System.out.println("found: "+m.group()); 
    System.out.println("website: "+m.group(1)); 
    System.out.println("description: "+m.group(5)); 
} 
System.out.println("done"); 
9

以供將來參考,還可以使用Pattern.DOTALL標誌爲「。」甚至匹配\ r或\ n。

實施例:

說出我們正在分析的HTTP標頭行這樣的(每一行\ r \ n結束)

HTTP/1.1 302 Found 
Server: Apache-Coyote/1.1 
Cache-Control: no-cache, no-store, max-age=0, must-revalidate 
Pragma: no-cache 
Expires: 0 
X-Frame-Options: SAMEORIGIN 
Location: http://localhost:8080/blah.htm 
Content-Length: 0 

該圖案的單個串:

final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL); 

可以使用「matcher.group(1)」解析位置值。

「。」在上面的模式中會匹配\ r和\ n,所以上面的模式實際上可以從http標題行解析'Location',在標題行之前或之後可能會有其他標題(不是推薦的方式解析http標題)。

此外,您可以在模式內使用「?s」來達到相同的效果。

如果你這樣做,你可能會更好使用Matcher.find()。

+0

DOTALL在這種情況下並不真正有用。 OP需要知道正則表達式何時消耗行分隔符,因此他可以確定他只匹配其中的一個。在你的例子中,所有感興趣的內容都包含在一行中,它就更沒用了。我很少使用DOTALL模式;它似乎會導致比解決問題更多的問題。 – 2015-05-19 05:20:50

+0

你可能是對的,但它在我的例子中很有用,但我的單個字符串解析實際上具有所有的行。 – javaPhobic 2015-05-19 05:28:26

+0

有關DOTALL模式的事情是它極大地擴大了惡作劇的範圍。例如,當我將你的正則表達式應用到你的示例數據時,第一個'。*?'消耗'Location'頭部上面列出的所有頭部。我知道你只關心你在第一組中捕獲的URL,但是你仍然可以在DOTALL模式關閉的情況下得到它,並且你將爲正則表達式節省很多不必要的工作。 – 2015-05-19 08:36:01