Поиск всех комбинаций групп захвата с регулярным выражением - PullRequest
2 голосов
/ 27 февраля 2020

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

Учитывая строку Max Michael van Mustermann Я хочу сгенерировать пары (Max)(Michael van Mustermann), (Max Michael)(van Mustermann) и (Max Michael van)(Mustermann).
Это должен быть выполнимым по шаблону ^(.+) (.+)$ (где пробел - это разделительный символ). Однако это не работает так, как задумано, поскольку первая группа захвата жадно захватывает Max Michael van, оставляет Mustermann второй группе захвата и завершает оценку, поскольку вся строка была сопоставлена.

Я пытался использовать решения для перекрывающихся матчей ((?=<regex>)), но это не дало желаемых результатов (поглощение одного символа за другим с фронта, но по-прежнему жадным, как и раньше).

Я пытался сделать первую группу захвата ленивой, но это только решает проблему. Никакая комбинация лени и / или жадности не приведет к совпадению (Max Michael)(van Mustermann).

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


Моя настоящая проблема:
У меня есть список имена в виде строк. Я не знаю, где их разделить по имени и фамилии. Однако у меня есть другой список с теми же именами, но с обратными именами и фамилиями.

Моя идея состоит в том, чтобы найти все комбинации групп захвата в первом списке, изменить их порядок и сопоставить их против второго списка.

# First list
Max van Mustermann
Miriam Musterfrau
Alice Bobina Charlston

# Second list
van Mustermann Max       (van is part of last-name)
Musterfrau Miriam
Charlston Alice Bobina   (Bobina is part of first-name)

Какой-то примерно желаемый код:

String first = "Max van Mustermann";
String second = "van Mustermann Max";

Pattern pattern = Pattern.compile("^(.+) (.+)$");
Matcher matcher = pattern.matcher(first);
while (matcher.find()) { // This is obviously not correct, it will only find the first match
    String swapped = matcher.group(2) + " " + matcher.group(1);
    if(second.equals(swapped)){
        // Success!
    }
}

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

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

Я нашел регулярное выражение, которое делает почти то, что вы хотите:

String first = "Alice Bobina Charlston Max van Mustermann Miriam Musterfrau";
Pattern pattern = Pattern.compile("(?<=^(.*)\\G)( ?\\w+)(?= (.*$))");
Matcher matcher = pattern.matcher(first);
while (matcher.find()) {
  System.out.printf("(%s)(%s)%n", matcher.group(1) + matcher.group(2), matcher.group(3));
}

Вывод:

(Alice)(Bobina Charlston Max van Mustermann Miriam Musterfrau)
(Alice Bobina)(Charlston Max van Mustermann Miriam Musterfrau)
(Alice Bobina Charlston)(Max van Mustermann Miriam Musterfrau)
(Alice Bobina Charlston Max)(van Mustermann Miriam Musterfrau)
(Alice Bobina Charlston Max van)(Mustermann Miriam Musterfrau)
(Alice Bobina Charlston Max van Mustermann)(Miriam Musterfrau)
(Alice Bobina Charlston Max van Mustermann Miriam)(Musterfrau)

Единственное отличие состоит в том, что он разбивает текст на 3 группы, а не 2, и вы должны вручную объединить первые две группы, чтобы получить результат. С этим шаблоном ваш код будет выглядеть так:

String first = "Max van Mustermann";
String second = "van Mustermann Max";

Pattern pattern = Pattern.compile("(?<=^(.*)\\G)( ?\\w+)(?= (.*$))");
Matcher matcher = pattern.matcher(first);
while (matcher.find()) { 
  String swapped = matcher.group(3) + " " + matcher.group(1) + matcher.group(2);
  if(second.equals(swapped)) {
    // Success!
  }
}

Волхвы c выполняются путем привязки шаблона к позиции последнего совпадения с помощью \G.

Это решение не так эффективно, как мое предыдущее решение, но просто доказывает, что то, что вы просите, достижимо с помощью регулярного выражения.

0 голосов
/ 27 февраля 2020

Ну, я не думаю, что это возможно сделать с помощью поиска по одному регулярному выражению. Однако вы можете сделать это с помощью одного поиска и одного сравнения:

String first = "Max van Mustermann";
String second = "van Mustermann Max";

Pattern pattern = Pattern.compile("^(.*)" + Pattern.quote(second) + "(.*)$");
Matcher matcher = pattern.matcher(first + " " + first);
if (matcher.matches()) {
  if ((" " + second + " ").equals(matcher.group(2) + " " + matcher.group(1))) {
    // Success!
  }
}

Объяснение: мы создаем строку, которая является «удвоенной» первой строкой:

Макс ван Мустерманн Макс van Mustermann

Если вторая строка является просто повернутой копией первой строки, то она должна соответствовать этой удвоенной первой строке:

Max van Mustermann Max van Mustermann

Затем нам нужно проверить, что то, что покоится на удвоенной строке, равно второй строке. Нам просто нужно взять окончание «ван Мустерманн» и добавить его к началу «Макс». Результат должен быть равен второй строке, дополненной пробелами с обеих сторон:

" van Mustermann" + " " + "Max " => " van Mustermann Max "
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...