【问题标题】:Finding words within a string in Java在Java中查找字符串中的单词
【发布时间】:2015-12-16 19:18:20
【问题描述】:

我基本上是在用 Java 编写“grep”,但我认为我不理解这些约定。假设以下代码块:

public class HelloWorld {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("this");
        Matcher m = p.matcher("this file has one line");
        System.out.println(m.matches());
    }
}

上面的代码打印出“false”

据我了解,模式“this”应该在字符串“this file has one line”中找到

这是我的语法错误还是我对 Pattern 或 Matcher 约定的理解有误?

编辑: 给定代码:

Matcher m = MY_PATTERN.matcher("FOO[BAR]");
    while (m.find()) {
    String s = m.group(1);
    // s now contains "BAR"
}

如何检索包含指定模式的整行?

【问题讨论】:

  • 您的代码不是在字符串中寻找"this",而是在查看该字符串是否与"this" 正则表达式字符串完全匹配,但它不匹配,所以@ 987654327@ 正确返回。
  • 您可能想了解String类docs.oracle.com/javase/7/docs/api/java/lang/…中的contains
  • 尝试使用find 而不是matches
  • 如果您必须为此使用正则表达式,请参阅stackoverflow.com/a/600740/1413133
  • 即使grep 也不在乎“文字”; echo thisissomething|grep this 将打印 thisissomething。消除了这种误解,您想要的是使用 .find(),而不是 .matches()。是的,.matches() 的名字很糟糕,第一次就抓住了所有人(.matches() 不进行正则表达式匹配,因为定义了正则表达式匹配)。

标签: java regex grep


【解决方案1】:

您的代码不是检查您的字符串是否包含"this",而是检查您的字符串是否等于 "this"。所以m.matches()的返回是正确的。

对于您正在寻找的功能,您不需要模式匹配器。 String.contains() 做你想做的事。

如果你真的需要使用正则表达式,那么这可能是你应该写的:

public class HelloWorld {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("this");
        Matcher m = p.matcher("this file has one line");
        System.out.println(m.find()); // will print true
    }
}

【讨论】:

    【解决方案2】:

    Matcher.matches() 当且仅当 whole 字符串与给定的正则表达式匹配时才返回 true。

    如果您正在寻找部分匹配,您可以选择:

    • 修改您的正则表达式:Pattern.compile(".*this.*"),或
    • 使用Matcher.find():System.out.println(m.find());,或
    • 如果您不需要正则表达式的强大功能,而是在寻找文字部分匹配,请使用String.contains()

    【讨论】:

    • 问题是正则表达式没有“部分匹配”;正则表达式匹配或不匹配。根据定义,它可以匹配其输入中的任何位置这就是为什么名称.matches() 的选择如此糟糕的原因。
    • @fge,与其他正则表达式实现相比,我同意 Java 的 Matcher.matches()(以及因此 String.matches())的行为是违反直觉的。然而,这就是它在 Java 中的完成方式......
    • 是的,我完全意识到这一点,而且这些年来我仍然对糟糕的命名选择感到愤怒:/ 嗯。
    【解决方案3】:

    如果您真的想在 Java 中复制 grep,那么您将面临相当大的任务;例如,考虑以下调用:

    grep something somefile
    echo sometext | grep something
    grep -x something somefile
    grep -Fx something somefile
    

    那里有很多选择。

    现在,让我们解决基本问题。

    第一个问题是.matches() 方法,无论是String 还是Matcher,都是用词不当。根据定义,如果正则表达式可以识别输入中的任何文本,则它匹配输入......不幸的是,Java API 不是这样定义.matches() 方法的。当且仅当整个输入与正则表达式匹配时,Java 的 .matches() 才会返回 true。

    因此,这不是您应该使用的。由于您使用Matcher,因此您想改用.find()

    第二个问题是逐行匹配;正则表达式通常不关心行;只是碰巧出现了一些定义这个概念的字符。同样,正则表达式不在乎。

    正则表达式并不关心,但是这个概念非常重要,Java 有类允许通过拆分必要的字符来将字符流分成“行”...所以这里是您将如何复制 grep 通过阅读来自标准输入,假设默认编码(为 Java 8+ 编写的代码):

    public static void main(final String... args)
    {
        if (args.length == 0)
            throw new IllegalArgumentException("missing pattern as an argument");
    
        final Pattern pattern = Pattern.compile(args[0]);
    
        final Charset cs = Charset.defaultCharset();
        final CharsetDecoder decoder = cs.newDecoder()
            .onMalformedInput(CodingErrorAction.REPORT);
    
        try (
            final Reader r = new InputStreamReader(System.in, decoder);
            final BufferedReader reader = new BufferedReader(r);
        ) {
            String line;
            while ((line = reader.readLine()) != null)
                if (pattern.matcher(line).find())
                    System.out.println(line);
        }
    }
    

    【讨论】:

      【解决方案4】:

      感谢所有cmets!

      我的解决方法如下:

      public static void main(String[] args) throws FileNotFoundException {
          String s = "this is line one\n"
                  + "this is line two\n"
                  + "This is line three";
      
          Pattern p = Pattern.compile("this");
      
          Scanner scanner = new Scanner(s);
          while (scanner.hasNextLine()) {
              String line = scanner.nextLine();
              Matcher m = p.matcher(line);
              if (m.find()) {
                  System.out.println(line);
              }
          }
      }
      

      上面的代码打印出第 1 行和第 2 行,因为它们都包含“this”,但没有第 3 行,因为“This”大写。

      如果我们将正则表达式更改为“one”,它只会打印出第 1 行。

      【讨论】:

        猜你喜欢
        • 2015-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-02
        • 1970-01-01
        相关资源
        最近更新 更多