Java中的正则表达式:如何处理换行符

Java中的正则表达式:如何处理换行符,java,regex,line-breaks,Java,Regex,Line Breaks,我目前正在学习如何使用正则表达式,所以请记住我的简单问题。例如,假设我有一个输入文件,其中包含一组由换行符分隔的链接: 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 苹果网站的描述 如果我想得到一个网站及其描述,这个正则表达式似乎可以在一个测试

我目前正在学习如何使用正则表达式,所以请记住我的简单问题。例如,假设我有一个输入文件,其中包含一组由换行符分隔的链接:

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
苹果网站的描述

如果我想得到一个网站及其描述,这个正则表达式似乎可以在一个测试工具上使用:
*www.*\\s.*Pig.

然而,当我尝试在代码中运行它时,它似乎不起作用。这个表达正确吗?我尝试将“\s”替换为“\n”,但它似乎仍然不起作用。

对我有效:

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");
    }
  }
}

可能是您使用图案和匹配器对象的方式有问题?

在您的文件中,行可能由
\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\n
,还包括。这相当于:

\r\n |[\n\x0B\x0C\r\u0085\u2028\u2029]
以下是您可以如何使用它:

(?im)^.*www.\R.*清管器*$
i
选项使其不区分大小写,
m
将其置于多行模式,允许
^
$
在行边界处匹配。

试试这个

([^\r]+\r[^\r])+

此版本匹配可能是Windows(\r\n)或Unix(\n)的换行符


为了便于将来参考,还可以使用“.”的Pattern.DOTALL标志匹配偶数\r或\n

例如:

假设我们正在解析一个http头行字符串,如下所示(每行以\r\n结尾)

这种模式:

final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL);
可以使用“matcher.group(1)”分析位置值

上述模式中的“.”将匹配\r和\n,因此上述模式实际上可以从http头行解析“位置”,在目标行之前或之后可能有其他头(这不是解析http头的推荐方法)

此外,您还可以在模式内部使用“?s”来实现相同的效果

如果要这样做,最好使用Matcher.find()

上述示例适用于选项卡空间、换行符和普通空间。
我使用了
java.lang.String
的trim方法来删除'str'中的所有额外空格。我希望这能帮助您和这里的其他优秀人士。

这只适用于始终使用\n格式化行的情况,因为在UnixTotal中,在这种情况下并不真正有用。OP需要知道正则表达式何时使用行分隔符,这样他就可以确保只匹配其中一个。在您的示例中,它甚至没有那么有用,因为所有感兴趣的内容都包含在一行中。我几乎从不使用DOTALL模式;它造成的问题似乎比它解决的问题还多。你可能是对的,但在我的示例中它很有用,我要分析的单个字符串实际上包含了所有行。DOTALL模式的一个特点是它极大地扩展了恶作剧的范围。例如,当我将正则表达式应用于示例数据时,第一个
*?
将使用
位置
标题上方列出的所有标题。我知道您只关心在组#1中捕获的URL,但在关闭DOTALL模式的情况下仍然可以获取该URL,并且可以为正则表达式节省大量不必要的工作。不,没有DOTALL,它将无法与“.”匹配\r或\n。因此,无法解析该位置。如果我基于行边界分割字符串,只将位置行输入正则表达式,而不使用DOTALL,那么它将起作用。不,我的意思是你不必匹配任何行分隔符
“Location:(.*)”
可能会很好,但为了安全起见,我会使用锚定:
“(?m)^Location:(.*)$”
raw'\R'是不允许的java 8 final:/@Davinder Singh的答案有两个反斜杠来补偿java编译器对字符串文本的解码。也许,Joe的观察与尝试在新的regexp字母后面使用一个反斜杠有关。这可能会在编译时变成非法的Java字符串文字。按照Davinder的例子,我想使用双反斜杠应该对Joe有用。只是提醒一下可能更简单的解决方案:对于我自己的例子,使用显式
\n
,甚至使用
模式的建议。DOTALL
/
(?s)
和双转义(\\),如下所述,我发现这一点非常微妙,可以回到非regexp字符串方法<代码>str.contains(“\n”)工作正常<代码>str.replaceAll(“\n”,replacement)也起作用。在Java 11中,我找不到返回true的
String.matches
Pattern.compile的变体。(与下面的解决方案不同
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);
String str="I am  a   "+"\n  Man    of  Peace"+"\t"+"   .";

str=str.replaceAll("[\\s|\\t|\\r\\n]+"," ").trim();
System.out.println(str);