Сканирование файла и сбор полного слова, соответствующего шаблону - PullRequest
0 голосов
/ 31 января 2019

Я работаю над проектом, в котором мне нужно отсканировать папку и отсканировать каждый файл на предмет определенного слова (скажем, «@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.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

вот мое решение:

    // 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 и т. Д.).
  • \\(.+\\) соответствует некоторому тексту в скобках (например, * 1028).*, где скобки тоже должны быть экранированы \\( и \\) и .+ для любого непустого текста внутри

Примечание: неэкранированные скобки имеют особое значение внутри любого регулярного выражения, то есть группировка и захват

Соответствующие скобки и извлечение их содержимого см. в этом ответе на Шаблон для извлечения текста в скобках .

извлечение текста с использованием групп захвата внутри регулярного выражения

Просто используйте круглые скобки (без экранирования), чтобы сформировать группу, и запомните их номер заказа. (grouped)(Regex) будет соответствовать тексту groupedRegex и может извлечь две группы:

  • группа № 1: grouped
  • группа № 2: Regex Чтобы получить эти группы, используйте matcher.find(), а затем matcher.group() или его перегруженные методы.

опция для проверки регулярного выражения и извлечения

В IntelliJ вы можете использовать действие Проверить RegExp в IntelliJ: ALT + Введите в выбранном регулярном выражении, чтобы проверить и адаптировать его.Похоже есть довольно много сайтов для проверки регулярных выражений.Например, http://www.regExPlanet.com также поддерживает синтаксис Java-RegEx, и вы можете проверить извлеченные группы в режиме онлайн.См. пример на RegexPlanet .

Примечание: есть одно особое значение каретки, кроме начало , как Оле ответил выше : это[^)]+ означает совпадение с чем угодно (не менее 1 символа) , кроме закрывающих скобок

делает его расширяемым с помощью функции экстрактора

Если вы замените экстракт-Функция, используемая в качестве аргумента для .map(..) выше, следуя которой вы также можете напечатать аннотацию-имя и текст внутри скобок (разделенные табуляцией):

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
  • вы пытались получить исправление с помощью скобок
  • в вашем регулярном выражении была синтаксическая ошибка или опечатка, каретка ^
  • не использовала экранированные скобки \\( и \\) вы бы получили не только текст-внутри, а также скобки как экстракт
0 голосов
/ 31 января 2019

То, как вы используете ^(.+), не имеет смысла в регулярном выражении.^ соответствует началу строки (строки), но начало строки не может следовать за шаблоном (только если шаблон будет соответствовать пустой строке, чего здесь нет).Таким образом, ваш шаблон никогда не может совпадать ни с одной строкой.

Просто используйте:

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

Если вам требуется, чтобы после шаблона не было никаких символов (даже пробелов), $ соответствует концустроки:

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