多行字符串的Java正则表达式模式

p8ekf7hl  于 2023-01-19  发布在  Java
关注(0)|答案(2)|浏览(121)

我正在使用一个简单的java正则表达式程序来检查一组字符串是否与定义的正则表达式模式匹配。我创建了一个reg-ex模式,但运行时显示为false。我需要修改reg-ex模式以匹配给定的字符串。下面是我的源代码:

String thread = "From: Demo Name\n" +
                "Sent: Wednesday, January 18, 2023 2:56 PM\n" +
                "To: demo@myweb.com <demo@myweb.com>\n" +
                "Subject: Demo Issue";
        String regEX ="((^[a-zA-Z]+[:]\\s.*\\n*?\\n){2,4}.+\\nSubject[:].+\\n)+?";

        Pattern pattern = Pattern.compile("((^[a-zA-Z]+[:]\\s.*\\n*?\\n){2,4}.+\\nSubject[:].+?\\n)+?",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(thread);
        System.out.println(matcher.find());

运行程序时返回false。但预期返回true。在给定的字符串中,诸如From:Sent:To:Subject:等单词是常量,不会改变。需要根据需要修改reg-ex模式。

pgccezyw

pgccezyw1#

^匹配整个输入的开头,除非您启用MULTILINE模式,在这种情况下,它匹配任何“行的开头”。因此,您 * 确实 * 希望MULTILINE模式,以便您的^[a-zA-Z]+:\\s.*模式匹配标题,而不是实际文本中间冒号的随机用法。注意,如果有人将“Foo:bar'在它自己的行上,你也要匹配它,仅仅用正则表达式你做不了什么。
然后,您尝试匹配一个应该占用1个标题行2到4次的内容。然后,您需要一个看似任意插入的.+,这会使您陷入混乱,因为这意味着Subject无法再匹配。摆脱它。您还到处都是\\n,太频繁了。感觉就像你只是把东西塞进去,祈祷只要你加够了,也许就会起作用。
这不是你做正则表达式的方法。当它们不起作用时让它更小,而不是更大-尝试只匹配第一行。然后从那里扩展。不断地从“匹配”到“匹配”,而不是在你觉得应该匹配的时候从不匹配的东西开始,然后徒劳地把东西塞进正则表达式。
这里最后一个技巧是你的输入字符串**没有以换行符结尾,但是你在正则表达式中要求Subject:行以换行符结尾。它没有这样做,所以这不起作用。使用^$确实起作用,因为它们在输入结束时也匹配。
使用我为正则表达式修正的策略:

String regEX ="((^[a-zA-Z]+[:]\\s.*\\n*?\\n){2,4}.+\\nSubject[:].+\\n)+?";
// use flags CASE_INSENSITIVE and MULTILINE but not DOTALL.

不要使用DOTALL --这意味着.*会吃掉所有内容(包括换行符,这是您不想要的)。
但是
这个正则表达式似乎是不明智的。你 * 实际上 * 想要完成什么?如果输入是'constant',为什么不直接抛弃正则表达式,搜索"\nSubject: "?如果你想去掉所有的标题,为什么不搜索分隔标题和正文的双回车键,然后去掉其余的呢?

int headerSplit = in.indexOf("\n\n");
String bodyOnly = in.substring(headerSplit + 2);

如果你想把这些东西结合起来,那么就这样写。“把所有东西都放在一个巨大的正则表达式中”很少是让代码易于维护的方法。如果这是一个完整的新闻/邮件消息,那么首先找到空行,这样你就可以把标题和内容分开(毕竟,在电子邮件中写入Foo: bar是完全法律的的,并不意味着它有Foo标头!),* 然后 * 如果您想特别选择主题,则可以编写一个regex或,你其实并不需要

void getSubjectFromEmail(String in) {
  int headerEnd = in.indexOf("\n\n");
  int subject = in.indexOf("Subject: ");
  if (headerEnd != -1 && subject > headerEnd) return null;
  int subjectEnd = in.indexOf('\n', subject);
  return in.substring(subject + "Subject: ".length(), subjectEnd == -1 ? in.length() : subjectEnd);
}

不用正则表达式也能做到。正则表达式不擅长查找“头的结尾”位。如果你喜欢,可以使用混合方法:

class Test {
  private static final Pattern SUBJECT_FINDER = Pattern.compile("^Subject: (.*)$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

  String getSubjectFromEmail(String in) {
    int headerEnd = in.indexOf("\n\n");
    var m = SUBJECT_FINDER.matcher(in);
    if (headerEnd != -1) m.region(0, headerEnd);
    if (!m.find()) return null;
    return m.group(1);
  }

  static final String TEST_TEXT = """
    From: Demo Name
    Sent: Wednesday, January 18, 2023 2:56 PM
    To: demo@myweb.com <demo@myweb.com>
    Subject: Demo Issue"""
    .replace("\r", "");

  void test() {
    String subject = getSubjectFromEmail(TEST_TEXT);
    System.out.println("Subject found: " + subject);
  }

  public static void main(String[] args) {
    new Test().test();
  }
}
fwzugrvs

fwzugrvs2#

您的模式匹配结尾处的换行符,但示例数据的结尾处没有换行符。
如果常量在字符串中从不更改,则使用\h匹配水平空白字符,使用\R匹配任何unicode换行符序列:

^From:\h+.+\RSent:\h+.+\RTo:\h+.+\RSubject:\h+.*

在Java中,使用 Pattern.MULTILINEPattern.CASE_INSENSITIVE 以及双反斜杠:

String regEX = "^From:\\h+.+\\RSent:\\h+.+\\RTo:\\h+.+\\RSubject:\\h+.*";

Regex101 demo|Java demo
如果要匹配2-4行,然后是Subject:

(?:^[a-z]+:\h.*\R){2,4}Subject:.*

在Java中,使用 Pattern.MULTILINEPattern.CASE_INSENSITIVE 以及双反斜杠:

String regEX = "(?:^[a-z]+:\\h.*\\R){2,4}Subject:.*";

Regex101 demo|Java demo

相关问题