【问题标题】:Finding a word in text在文本中查找单词
【发布时间】:2014-02-26 22:53:19
【问题描述】:

以下代码似乎可以正常工作

String key = "jumps"   
String text = "the quick brown fox jumps over the lazy dog";  
if (text.matches(".*\\b"+key+"\\b.*"))
    System.out.println("Match");

if 语句为 TRUE,我得到 MATCH 以打印输出。 但这是我需要做的:
创建一个名为 text.txt 的文件,并在其中放入“快速棕色狐狸跳过懒狗”。

String text = new Scanner( new File("test.txt") ).useDelimiter("\\A").next();
String key = "jumps" 
if (text.matches(".*\\b"+key+"\\b.*"))
    System.out.println("Match");

这种匹配似乎只有在 test.txt 文件中只有一行时才有效。
如果文件中有一行 - if 语句为 TRUE。
如果我用两行创建文件 -
敏捷的棕色狐狸跳过了懒惰的狗
敏捷的棕狐跳过懒狗

那么 if 语句似乎永远不会是真的。
关于为什么以及我可以做些什么来让这个匹配与文件一起工作的任何想法?

【问题讨论】:

标签: java pattern-matching match java.util.scanner


【解决方案1】:

. 不匹配换行符,所以当你有一个新行时,它会失败。使用\s 匹配换行符。

我不是正则表达式专家,但(.|\s) 是一种 将两者结合起来的方式,使用|(OR 符号)。该组合应匹配任何字符,包括换行符。因此,你的表达变成了

"(.|\\s)*\\b" + key + "\\b(.|\\s)*"

【讨论】:

  • 对不起,也许我在这里有点厚,但我尝试了我认为你的意思。我可以请你更具体一点我如何改变 (".*\\b"+key+"\\b.*") 因为我不想影响我只寻找整个单词.感谢您的宽容。
  • @harry 我想我犯了一个错误,你发现了。更新了答案。
  • 感谢帮助,但有这个 - if (text.matches("(.|\\n)*\\b"+key+"\\b(.|\\n)*") ) 只有一行时仍然有效,多行时无效。
  • @Harry 我实际上下载了 Netbeans 并为您解决了这个问题。看起来 \n 并不总是捕获行之间的所有字符(尤其是对于由记事本或 Windows 的 Netbeans 保存的文件)。我恢复使用 \s,但留在 \b 以保持单词边界。经过测试,它可以工作。
  • 谢谢。我感谢您的帮助。这确实可以正常工作。我发现的问题是添加 \s 会使匹配非常非常缓慢。事实上,如果我尝试在我的计算机上匹配超过 150 个字符的内容,它就会挂起并且似乎不会从匹配中返回。它工作正常,虽然在较短的字符串上运行缓慢。
【解决方案2】:

为什么不使用indexOf?

例如:

String text = new Scanner( new File("test.txt") ).useDelimiter("\\A").next();
String key = "jumps";
if (Arrays.asList(text.split("[\\s]")).indexOf(key) != -1)
    System.out.println("Match");
else
    System.out.println("No match");

这个解决方案的好处是它还可以告诉你它是序列中的哪个单词;但是,对于非常大的字符串,它可能不会很快。

如果你真的想使用正则表达式,你需要使用\s,因为新行可以用\n、\r或\r\nand \s can be any of these来表示。所以,你需要这样的东西:

编辑:改用以下正则表达式:"(?s:.*\\b"+key+"\\b.*)"。

if (text.matches("(.|\\s)*\\b"+key+"\\b(.|\\s)*"))
    System.out.println("Regex: Match");
else
    System.out.println("Regex: No match");

如果您要在非常大的文件中查找单词,您可能需要查看StringSearch。只需下载jar,将其添加到您的classpath,并确保您是import com.eaio.stringsearch.*;

BNDMWildcards bndm = new BNDMWildcards();
int bndmIdx = 0;
int stopIdx = text.length();
boolean isFound = false;

while(!isFound && (bndmIdx = bndm.searchString(text, bndmIdx, stopIdx, "."+key+".")) != -1){
    char[] textChars = text.toCharArray();
    if(Character.isWhitespace(textChars[bndmIdx]) && Character.isWhitespace(textChars[bndmIdx+key.length()+1])){
        System.out.println("BNDM: Match");
        isFound = true;
    }
}
if(!isFound)
    System.out.println("BNDM: No match");

我不确定这种方法与其他两种方法相比在速度方面如何。我的猜测是短 text 需要更长的时间,但当 text 很长时会更快。

编辑:以前的regex 包含导致StackOverflowException 的可能性(非常适合这个网站!)- 我应该看到的问题。这是因为它在尝试搜索 text 时会创建大量子表达式。

您可以尝试的另一种正则表达式是"(?s:.*\\b"+key+"\\b.*)"。这启用了DOTALL,强制. 匹配所有字符。它应该只创建一个子表达式。

【讨论】:

  • 嗨..我如何让 indexOf 只做整个单词?如果我在寻找“他”,我不想找到“她”。并且可能有“,”或“。”或单词后的行尾,所以我不能只寻找“”。谢谢。
  • @Harry 更新了我的答案。
  • 嗨。好吧,我不得不说这个正则表达式做了我想要的正确的事情。但问题是它非常非常慢。每当我与超过 150 个字符的字符串进行比较时,它都会挂起并且不会在我等待的 10 分钟内返回。我所做的唯一更改是更改 "(.|\\n)*\\b"+key+"\\b(.|\\n)*"。我的错误方式立即生效。
  • 哇。谢谢!是的,您的解决方案会进行搜索,并且几乎会立即返回。所以感谢大家的建议。不过我很好奇。两种搜索的内在差异是什么使得旧方法的效率大大降低?是“|”吗运营商?
  • @Harry 问题在于它在尝试评估表达式时创建了大量的groups。如果您没有为 Java 分配太多内存,这很快就会导致StackOverflowException。如果你有很多,它只会运行很长时间。如果此答案有帮助,请考虑将其标记为已接受。
【解决方案3】:

你为什么不试试这个方法?

Scanner scanner = new Scanner(new File("test.txt"));
    String text = "" ;
    while(scanner.hasNext())
    {
        text=text+scanner.nextLine();
    }
 if (text.matches(".*\\b"+key+"\\b.*"))
System.out.println("Match");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-09
    • 2021-12-25
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2013-04-04
    • 2021-12-13
    • 1970-01-01
    相关资源
    最近更新 更多