【问题标题】:Scan a file and collect complete word matching a pattern扫描文件并收集匹配模式的完整单词
【发布时间】:2019-06-24 20:07:08
【问题描述】:

我正在做一个项目,我需要扫描一个文件夹并扫描每个文件中的特定单词(比如“@MyPattern”)。

我期待有一种最佳方法来设计这样的场景。 首先,我的工作如下:

    //Read File
    List<String> lines = new ArrayList<>();
    try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
        stream.forEach(line-> lines.add(line));
    } catch (IOException e) {
        e.printStackTrace();
    }

    //Create a pattern to find for
    Predicate<String> patternFilter = Pattern
            .compile("@MyPattern^(.+)")
            .asPredicate();

    //Apply predicate filter
    List<String> desiredWordsMatchingPattern = lines
            .stream()
            .filter(patternFilter)
            .collect(Collectors.<String>toList());

    //Perform desired operation
    desiredWordsMatchingPattern.forEach(System.out::println);

我不确定为什么这不起作用,即使文件中有多个匹配“@MyPattern”的单词。

【问题讨论】:

  • 建议:只需仔细检查您的正则表达式一次。
  • 看起来你的正则表达式有问题。
  • 我的字符串是这样的:“@Traces("10869") @Details('用户正在查看用户配置文件') 给出:用户对用户配置文件开放“我期待提取” 10869" 在@Traces 之后。 so 的正则表达式应该是什么
  • @MyPattern 这样的正则表达式将匹配@MyPattern 而没有别的,即它不会匹配@Traces(为什么要匹配?)。除此之外,您的谓词将选择包含匹配项的行,但不会提取匹配项。您可以为此使用Scanner
  • 当我问您是否会接受其中一个(非常不同的)答案时,我希望我不会让您陷入任何忠诚度冲突?未来的读者会发现知道哪个对您更有帮助很有帮助。见What should I do when someone answers my question?

标签: java string text java-8 string-matching


【解决方案1】:

这是我的解决方案:

    // can extract annotation and text-inside-parentheses
    private static final String REGEX = "@(\\w+)\\((.+)\\)";


    //Read File
    List<String> lines = Files.readAllLines(Paths.get(filename));

    //Create a pattern to find for
    Pattern pattern = Pattern.compile(REGEX);

    // extractor function uses pattern's second group (text-within-parentheses)
    Function<String, String> extractOnlyTextWithinParentheses = s -> {
        Matcher m = pattern.matcher(s);
        m.find();
        return m.group(2);
    };

    // all lines are filtered and text will be extracted using extractor-fn
    Stream<String> streamOfExtracted = lines.stream()
            .filter(pattern.asPredicate())
            .map(extractOnlyTextWithinParentheses);

    //Perform desired operation
    streamOfExtracted.forEach(System.out::println);

解释:

让我们首先澄清一下使用的正则表达式模式@(\\w+)\\((.+)\\)应该做什么:

假设:您过滤文本以获得类似 Java 的注释,例如 @MyPattern

使用正则表达式匹配特定行

  • @\\w+ 匹配一个 at 符号后跟一个单词(\\w 是特殊含义,代表单词,即字母和下划线)。因此它将匹配任何注释(例如@Trace@User 等)。
  • \\(.+\\) 匹配一些括号内的文本(例如("10869"),其中括号也必须转义\\(\\).+ 用于内部的任何非空文本

注意:非转义括号在任何正则表达式中都有特殊含义,即分组和捕获

有关匹配括号并提取其内容,请参阅Pattern to extract text between parenthesis 上的此答案。

使用正则表达式中的捕获组提取文本

只需使用括号(未转义)来组成一个组并记住他们的订单号。 (grouped)(Regex) 将匹配文本groupedRegex 并可以提取两个组:

  • #1 组:grouped
  • 组#2:Regex 要获取这些组,请使用 matcher.find(),然后使用 matcher.group() 或其重载方法。

测试正则表达式和提取的选项

在 IntelliJ 中,您可以在 IntelliJ 中使用 Check RegExp 操作:ALT+Enter 对选定的正则表达式进行测试和调整。 类似的有很多网站可以测试正则表达式。例如http://www.regExPlanet.com 也支持 Java-RegEx-Syntax,您可以在线验证提取的组。见example on RegexPlanet

注意:除了 开始 之外,插入符号还有一个特殊含义,例如 Ole answered above:这个 [^)]+ 表示匹配任何内容(至少 1 个字符)除了右括号

使用提取器功能使其可扩展

如果您将用作上述.map(..) 参数的extract-Function 替换为以下内容,您还可以同时打印注释名称和括号内的文本(制表符分隔):

Function<String, String> extractAnnotationAndTextWithinParentheses = s -> {
        Matcher m = pattern.matcher(s);
        m.find();
        StringBuilder sb = new StringBuilder();
        int lastGroup = m.groupCount();
        for (int i = 1; i <= lastGroup; i++) {
            sb.append(m.group(i));
            if (i < lastGroup) sb.append("\t");
        }
        return sb.toString();
};

总结:

您的流媒体有效。 您的正则表达式出错

  • 它几乎匹配了一个常量注解,即@MyPattern
  • 您尝试使用括号捕获正确性
  • 您的正则表达式中有一个语法错误或错字,插入符号^
  • 不使用转义括号 \\(\\),您不仅会得到 text-inside,还会得到括号作为摘录

【讨论】:

    【解决方案2】:

    您使用^(.+) 的方式在正则表达式中没有意义。 ^ 匹配字符串的开头(行),但字符串的开头不能出现在模式之后(仅当模式匹配空字符串时,它不在这里)。所以你的模式永远不会匹配任何行。

    只需使用:

            Predicate<String> patternFilter = Pattern
                    .compile("@MyPattern")
                    .asPredicate();
    

    如果您要求模式后面没有字符(甚至空格也不能),$ 匹配字符串的结尾:

            Predicate<String> patternFilter = Pattern
                    .compile("@MyPattern$")
                    .asPredicate();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-18
      • 1970-01-01
      相关资源
      最近更新 更多