Как извлечь параметры из вывода форматированной строки в Java - PullRequest
0 голосов
/ 26 апреля 2018

Я пытаюсь проанализировать вывод программы и извлечь параметры, использованные для генерации этих результатов. Выходные данные представлены в виде предложений, сгенерированных из функции форматирования в Python, например ::10000

  • Открытие браузера "Google Chrome" для базового URL-адреса "https://https://stackoverflow.com'. создается из открытия браузера"% s "в базовый URL-адрес"% s "

  • Нажатие на элемент 'xpath =. // a [содержит (normalize-space (@class), "cc-btn cc-dismiss")]'. создается из кликающего элемента "% s".

Я хочу извлечь начальные входные параметры в функции форматирования. Моя функция будет выглядеть примерно так:

private List<String> extractParameters(String output, String format){
  // code would come here
}

Функция принимает в качестве входных данных сгенерированную строку и строку формата, которая использовалась для ее генерации (например, «Нажатие на элемент«% s ».»), И возвращает отсортированный список использованных параметров (например, «xpath =. // a [содержит (normalize-space (@class), "cc-btn cc-dismiss")] ")

Я начал работать над методом с использованием регулярных выражений, но у меня есть много форматов для управления, и я не являюсь экспертом по регулярным выражениям, и решение, к которому я стремлюсь, действительно ужасно и не требует обслуживания. Итак, вопрос:

Есть ли какой-нибудь элегантный способ достичь своей цели элегантным способом на Java?

1 Ответ

0 голосов
/ 27 апреля 2018

Regex должен сделать свое дело, но вы должны быть уверены, что они оптимизированы и хорошо написаны. Для приведенных выше примеров я сделал простой анализатор строк на основе шаблонов регулярных выражений:

class RegexLineAnalyzer {

    private List<Pattern> patterns = new ArrayList<>();

    public RegexLineAnalyzer() {
        patterns.add(Pattern.compile("^Opening browser '(.+)' to base url '(.+)'", Pattern.CASE_INSENSITIVE));
        patterns.add(Pattern.compile("^Clicking element '(.+)'", Pattern.CASE_INSENSITIVE));
        // add other patterns
    }

    public List<String> extractParameters(String line) {
        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(line);
            if (matcher.find()) {
                List<String> parameters = new ArrayList<>(matcher.groupCount());
                for (int i = 0; i < matcher.groupCount(); i++) {
                    parameters.add(matcher.group(i + 1));
                }

                return parameters;
            }
        }

        return Collections.emptyList();
    }
}

Я предполагаю, что файлы журнала разбиты на строки. Как эффективно читать и разбивать файлы по строкам, вы можете найти на этой странице .

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {

    public static void main(String[] args) {
        List<String> lines = new ArrayList<>();
        lines.add("Opening browser 'Google Chrome' to base url 'https://https://stackoverflow.com'.");
        lines.add("Clicking element 'xpath=.//a[contains(normalize-space(@class), \"cc-btn cc-dismiss\")]'.");

        RegexLineAnalyzer regexLineAnalyzer = new RegexLineAnalyzer();
        for (String line : lines) {
            System.out.println(line + " => " + regexLineAnalyzer.extractParameters(line));
        }
    }
}

Печать:

Opening browser 'Google Chrome' to base url 'https://https://stackoverflow.com'. => [Google Chrome, https://https://stackoverflow.com]
Clicking element 'xpath=.//a[contains(normalize-space(@class), "cc-btn cc-dismiss")]'. => [xpath=.//a[contains(normalize-space(@class), "cc-btn cc-dismiss")]]

EDITED
Я думал, у вас есть список шаблонов, которые вы можете сопоставить с каждой строкой. Если вам нужно угадать шаблон, а затем проанализировать его и найти аргументы, вы можете использовать более простое решение на основе функции split. Мы должны предположить, что каждая строка содержит четное число символов '. У нас будут проблемы со строками типа: Jon's browser is 'IE' или User last name is 'O'Reilly', или мы можем столкнуться с User's last name is 'O'Reilly' Простая реализация может выглядеть так:

class SplitLineAnalyzer {

    public List<String> extractParameters(String line) {
        final String regex = "'";
        final String[] split = line.split(regex);
        if (split.length % 2 == 0) {
            System.out.println("Line contains unexpected number of parts. Hard to guess pattern for line = " + line);
            return Collections.emptyList();
        }

        List<String> args = new ArrayList<>();
        for (int i = 1; i < split.length; i += 2) {
            args.add(split[i]);
            split[i] = "%s";
        }

        Arrays.stream(split).reduce((s1, s2) -> s1 + regex + s2).ifPresent(s -> System.out.println("Possible pattern: " + s));

        return args;
    }
}

Пример использования:

public class Main {

    public static void main(String[] args) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("Opening browser 'Google Chrome' to base url 'https://https://stackoverflow.com'.");
        lines.add("Clicking element 'xpath=.//a[contains(normalize-space(@class), \"cc-btn cc-dismiss\")]'.");
        lines.add("'Firefox' is used by user 'Tom'.");
        lines.add("Lines like this' could be broken.");
        lines.add("User's first name is 'Jerry'.");
        lines.add("User's last name is 'O'Reilly'");

        SplitLineAnalyzer regexLineAnalyzer = new SplitLineAnalyzer();
        for (String line : lines) {
            System.out.println(line + " => " + regexLineAnalyzer.extractParameters(line));
            System.out.println("");
        }
    }
}

Печать:

Possible pattern: Opening browser '%s' to base url '%s'.
Opening browser 'Google Chrome' to base url 'https://https://stackoverflow.com'. => [Google Chrome, https://https://stackoverflow.com]

Possible pattern: Clicking element '%s'.
Clicking element 'xpath=.//a[contains(normalize-space(@class), "cc-btn cc-dismiss")]'. => [xpath=.//a[contains(normalize-space(@class), "cc-btn cc-dismiss")]]

Possible pattern: '%s' is used by user '%s'.
'Firefox' is used by user 'Tom'. => [Firefox, Tom]

Line contains unexpected number of parts. Hard to guess pattern for line = Lines like this' could be broken.
Lines like this' could be broken. => []

Line contains unexpected number of parts. Hard to guess pattern for line = User's first name is 'Jerry'.
User's first name is 'Jerry'. => []

Line contains unexpected number of parts. Hard to guess pattern for line = User's last name is 'O'Reilly'
User's last name is 'O'Reilly' => []
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...