Мне нужно обнаружить в контенте парольные фразы из четырех слов, которые представляют собой последовательности от n до m слов. ВСЕ последовательности из четырех слов должны быть обнаружены, даже те, которые частично перекрываются, что является моей проблемой, поскольку я знаю только, как написать последовательность, которая потребляет четыре слова, а затем переходит к следующей последовательности бродов, начинающейся в конце этого слова .

Например. если у меня есть последовательность:

Случайная правильная оловянная шляпа для лошади

И я использую:

([A-Za-z0-9] +) {4} ([A-Za-z0-9] +)

Он найдет только:

  • случайная правильная батарея лошади

А также

  • оловянная шляпа

Но вместо этого мне нужно найти все следующее:

  • случайная правильная батарея лошади

  • правильная скоба для лошадиных аккумуляторов

  • ошибка скоба батареи лошади

  • аккумуляторная скоба жучок олово

  • оловянная шляпа

Итак, все четыре последовательности слов в предоставленной строке.

Я понимаю, что моя проблема в том, что мое регулярное выражение потребляет первые четыре слова, когда находит первое совпадение.

Кто-нибудь может объяснить, как создать регулярное выражение, которое «потребляет» только первое слово, а затем дает мне следующую допустимую последовательность, начиная со второго слова, и так далее?

Благодарность!

  • Пункт списка
2
Herby Sagues 7 Окт 2020 в 18:43

3 ответа

Лучший ответ

Как указано в комментариях, для сопоставления 4 слов квантификатор должен быть 3 вместо 4, чтобы всего было 4.

Поскольку вы сопоставляете символы [A-Za-z0-9], вы можете начать сопоставление с границы слова \b

Затем (если поддерживается) используйте положительный просмотр вперед, захватывая 4 слова в одной группе захвата.

\b(?=((?:[A-Za-z0-9]+ ){3}[A-Za-z0-9]+\b))
  • \b Граница слова
  • (?= Положительный просмотр вперед, утверждение прямо справа -
    • ( Захват группа 1
      • (?:[A-Za-z0-9]+ ){3} Повторить 3 раза, сопоставив более 1 раз класс символа и пробел.
      • [A-Za-z0-9]+\b Соответствует 1+ раз любому из перечисленных, за которым следует граница слова
    • ) Закрыть группу 1
  • ) Близкий взгляд вперед

Regex demo

Обратите внимание , что в отличие от шаблона, который вы пробовали, квантификатор повторяет группу без захвата (?:[A-Za-z0-9]+ ){3}, потому что повторение группы захвата возвращает только захват для последней итерации.

Нет языка с тегами, но, например, в Javascript

const regex = /\b(?=((?:[A-Za-z0-9]+ ){3}[A-Za-z0-9]+\b))/g;
const str = `random correct horse battery staple bug tin hat`;
let m;

while ((m = regex.exec(str)) !== null) {
  // This is necessary to avoid infinite loops with zero-width matches
  if (m.index === regex.lastIndex) {
    regex.lastIndex++;
  }
  console.log(m[1]);
}
0
The fourth bird 9 Окт 2020 в 09:20

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

Regex lookahead, lookbehind и атомные группы

Это может помочь:

Это не решается только с помощью регулярного выражения. Это сочетание «скользящего окна» и соответствия четырех «слов»:

public static void main(String[] args) {
    String input = "random correct horse battery staple bug tin hat";
    String[] arr = input.split("\\s+");

    Pattern pattern = Pattern.compile("([A-Za-z0-9]+\\s){4}");

    for (int i = 0; i <= arr.length - 4; i++){
        String fourWords = String.format("%s %s %s %s ", arr[i], arr[i + 1], arr[i + 2], arr[i + 3]);
        Matcher matcher = pattern.matcher(fourWords);

        if(matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

Выход:

random correct horse battery
correct horse battery staple
horse battery staple bug
battery staple bug tin
staple bug tin hat 
0
DigitShifter 7 Окт 2020 в 19:12

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

Разделите строку и работайте с токенами, например

List<String> words = Arrays.asList(sentence.split(" "));
List<List<String>> fourGrams = new ArrayList<>();
for (int i = 0; i < array.length - 4; i++) {
    fourGrams.add(words.subList(i, i + 4));
}
0
Bohemian 7 Окт 2020 в 19:18