使用Java正则表达式在句子中查找多个匹配词

3
我有一个句子和一组单词,比如Mayweather,undefeated等。我想要做以下两件事:
1. 检查句子中是否包含上述任何单词...(只查找匹配的单词,忽略句号、逗号和换行符等)。 2. 如果句子中包含这些单词,则需要显示每个匹配单词前后的几个单词,可以使用String.format()实现。
以下是我的代码,它似乎可以工作,但不完全符合我的要求:
String sentence = "Floyd Mayweather Jr is an American professional boxer " +
            "currently undefeated as a professional and is a five-division world champion, " +
            "having won ten world titles and the lineal championship in four different weight classes.";

    String newText = "";
    Pattern p = Pattern.compile("(Mayweather) .* (undefeated)");
    Matcher m = p.matcher(sentence);

    if (m.find()) {
        String group1 = m.group(1);
        String group2 = m.group(2);

        newText = String.format("%s ... %s" , group1, group2);
        System.out.println(newText);
    }

现在的输出是:

Mayweather ... 不败

我想要的是这样的:

Floyd Mayweather Jr是一位美国人,目前作为职业拳击手仍然不败...

您能告诉我如何做到这一点,或指导我正确的方向吗?因为我卡住了。
提前感谢!

为什么不使用contains()来检查,使用replaceAll()来替换呢? - TheLostMind
我不确定你的意思,但我不想替换句子中的文本,我只想以某种方式显示相同的内容。如果您指的是其他事情,请澄清或向我展示一个例子。谢谢。 - Musa
3个回答

2

如果您确实想通过正则表达式解决这个问题,您需要让捕获组匹配您想要输出的所有内容。目前,它们仅匹配您的搜索词:

(Mayweather) .* (undefeated)
// "Mayweather", "undefeated"

您可以尝试以下代码(只使用一个组!)来匹配您的整个示例:
(.*Mayweather.*undefeated.*)
// -whole text-

为了再次匹配这两部分,并且前后最多有12个字符(中间不要使用空格并将其非贪婪化!),可以将其更改为以下内容:

(.{0,12}Mayweather.{0,12}).*?(.{0,12}undefeated.{0,12})
// "Floyd Mayweather Jr is an Am", "r currently undefeated as a profes"

这可以进一步优化,以在单词边界处停止(结果需要修剪):

(\b.{0,12}Mayweather.{0,12}\b).*?(\b.{0,12}undefeated.{0,12}\b)
// "Floyd Mayweather Jr is an ", " currently undefeated as a "

将其更改为输出固定数量的单词留给无聊的读者作为练习。

编辑:修正了最后两个版本中“.*”的贪婪性(添加了“?”)。


似乎可以工作,伙计,谢谢。还有一件小事,如果我决定在第二个匹配中显示句子的其余部分,我该怎么做,例如“弗洛伊德·梅威瑟是一位”,“目前作为职业选手保持不败,并且是五个级别的世界冠军,曾经赢得过……”? - Musa
@M_Y 在这种情况下,您可以使用undefeated.*来匹配字符串的其余部分。或者如果您确定句子以句号结尾,则可以使用undefeated[^.]*\. - mkm13
1
谢谢,伙计。你的回答比下面那个好多了。我接受了你的回答。 - Musa
我对上面的方法有些小问题,也许很简单。假设我使用了"(\b.{0,15} Mayweather.{0,15}\b).? (\b.{0,15} undefeated.)",它在上面的句子中运行得很好,输出是 "Floyd Mayweather Jr is an ... currently undefeated as a ....",但如果有另一个句子匹配相同的单词,但是“undefeated”出现在“Mayweather”之前,则不会显示任何内容!你有什么想法如何解决这个问题吗? - Musa
你可以尝试匹配每个变体,即 A...BB..A。也许可以使用 (?:A|B)...(?:A|B),但那样会匹配 "...undefeated...undefeated..."。 - mkm13

0
你可以尝试下面这个,
注意:这只是一个原型,所以不要直接复制粘贴。
String str="Floyd Mayweather Jr is an American professional boxer currently undefeated as a professional and is a five-division world champion, having won ten world titles and the lineal championship in four different weight classes.";
    int firstIndex=str.indexOf("American");
    int secondIndex=str.indexOf("boxer");
    String group1=str.substring(0,firstIndex+"American".length()); // gives you 1st group

    String group2=str.substring(secondIndex);
    String newText = String.format("%s ... %s" , group1, group2);
    System.out.println(newText);

输出

弗洛伊德·梅威瑟是一位美国拳击手,目前作为职业选手保持不败纪录,并且是五个级别的世界冠军,赢得了十个世界冠军头衔和四个不同重量级别的线性冠军。


谢谢你的回答,伙计。我刚试了一下你的代码,当单词在句子开头时它可以正常工作,但如果单词在句子末尾或接近末尾,则会出现问题。例如,如果我从上面的句子中选择“世界”和“锦标赛”,那么它将显示从句子开头即“弗洛伊德·梅威瑟...”开始的所有文本,而我想要的是在它之前显示几个单词。我会尝试在我的端上进行调整,如果你有其他解决方案,请告诉我,我会接受你的答案。再次感谢你,伙计。 - Musa
@M_Y 告诉你这只是一个原型,这个逻辑的主要难点在于找到索引来创建组,你可以/应该改进这个逻辑!!我将索引保留为0仅作为示例,你可以使用任何你想要的值!! - Neeraj Jain

0

你的代码问题在于使用了分组。 正则表达式分组提供了你要识别的字符串片段。

group(0),也可以写作group = 整个字符串。

group(1)是你的第一个匹配项=“Mayweather”的第一次出现。

group(2)是你的第二个匹配项=“undefeated”的第一次出现。

你可以使用start(int group)和end(int group)方法找到你的匹配项的索引,然后对新字符串执行一些基本的字符串操作。

如果你打算专门使用正则表达式,你的解决方案如下:

      String sentence = ("Floyd Mayweather Jr is an American professional boxer " +
                  "currently undefeated as a professional and is a five-division                         world champion, " +
                  "having won ten world titles and the lineal championship in four      different weight classes.");

     /** Creates a StringBuilder, which can be altered, 
     *   unlike a string, which is immutable. */
     StringBuilder sb = new StringBuilder(sentence.length());

     Pattern p = Pattern.compile("(Mayweather) .* (undefeated)");
     Matcher m = p.matcher(sentence);

     if (m.find()) {
         int g1Start = m.start(1);
         int g1End = m.end(1);

         int g2Start = m.start(2);
         int g2End = m.end(2);

         sb.append(sentence.substring(0, g1Start));
         sb.append("...");
         sb.append(sentence.substring(g1End, g2Start));
         sb.append("...");
         sb.append(sentence.substring(g2End, (sentence.length() - 1)));

我不确定你是否需要在末尾添加换行符:

         sb.append("\r\n");

然后剩下的就很简单了:

         newText = sb.toString();
         textView.setText(newText);
     }

希望这能有所帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接