Regex: указанные слова в любом порядке

Я плохо разбираюсь в регулярных выражениях, пытаюсь сделать 2 регулярных выражения.

Регулярное выражение1:

All specified words in any order but nothing else. (repetition allowed).

Регулярное выражение2:

All specified words in any order but nothing else. (repetition not allowed).

Слова:

aaa, bbb, ccc

Струны:

aaa ccc bbb
aaa ccc
aaa bbb ddd ccc
bbb aaa bbb ccc

Регулярное выражение1 оценивает приведенные выше строки как:

true -> all word present in any order
false -> bbb is missing
false -> unknown word 'ddd'
false -> repetition not allowed

Регулярное выражение2 оценивает приведенные выше строки как:

true -> all word present in any order
false -> bbb is missing
false -> unknown word 'ddd'
true -> all word present in any order and repetition is allowed

Моя попытка

/^(?=.*\baaa\b)(?=.*\bbbb\b)(?=.*\bccc\b).*$/

Спрашиваю с целью обучения, поэтому, пожалуйста, уточните это.

Итак, некоторые символы, такие как пробелы, могут существовать между словами? Что еще может быть там?

revo 12.03.2019 09:07

разрешены только пробелы, новая строка, табуляция.

shajji 12.03.2019 09:17

Вы уверены, что между словами существуют новые строки?

revo 12.03.2019 09:21

k мой плохой, я думаю, я неправильно понял \b

shajji 12.03.2019 09:26

@revo разрешены только пробелы и табуляции.

shajji 12.03.2019 09:38

Пожалуйста, проверьте это regex101.com/r/Olu2kI/1

revo 12.03.2019 09:40

То, что вы можете использовать регулярное выражение, не означает, что вы должны это делать. var input = "ccc aaa ccc bbb"; var words = input.split(" "); var uniqueWords = Array.from(new Set(words)); console.info(uniqueWords.sort().join(" ") === "aaa bbb ccc");

Eric Duminil 12.03.2019 11:36

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

shajji 12.03.2019 11:49
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
12
8
281
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

зачем вам регулярное выражение для выполнения этой функции? вы можете легко добиться того, чего хотите, сначала разделив строки разделителем ",". Затем вы можете создать объект словаря со словами, которые вы ищете, поскольку ключи и значения по умолчанию равны -1.

Regex 2 можно получить, перебирая входные слова и проверяя, существуют ли они в качестве ключей в объекте словаря. Regex 1 может быть достигнут аналогичным образом, только когда ключ сопоставляется с входным словом, его значение затем будет изменено на 1, а при следующем посещении может быть возвращено ложное совпадение.

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

shajji 12.03.2019 09:14

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

Но для отдельных слов в регулярном выражении вы можете использовать \b

Пример: /\b(word1|word2|word3)\b/

как насчет порядка?

shajji 12.03.2019 09:14

@shajji это будет работать независимо от порядка. | (чередование) аналогично логическому ИЛИ

Code Maniac 12.03.2019 09:43

ты прав, но я собираюсь сделать кое-что другое, описанное в вопросе. хорошо спасибо за вашу помощь :).

shajji 12.03.2019 09:48
Ответ принят как подходящий

Для регулярного выражения 1:

var re = /^(?=.*?\baaa\b)(?=.*?\bbbb\b)(?=.*?\bccc\b)\b(?:aaa|bbb|ccc)\b(?: +\b(?:aaa|bbb|ccc)\b)*$/;
var res = document.getElementById('result');
res.innerText += re.test('aaa ccc bbb');
res.innerText += ', ' + re.test('aaa ccc ddd');
res.innerText += ', ' + re.test('aaa ddd bbb');
res.innerText += ', ' + re.test('ccc bbb ccc');
<div id = "result"></div>

Ваш код уже делает часть трюка. Ваши положительные прогнозы проверяют, что все слова где-то появляются, но не то, что они являются единственными присутствующими словами. Для этого я добавил циркумфлекс (^) в начале, чтобы определить начало строки. Затем не захватывающая группа \b(?:aaa|bbb|ccc)\b, чтобы обнаружить первый экземпляр любого слова. Затем следует любое количество слов, которым предшествует хотя бы один пробел (?:\s+\b(?:aaa|bbb|ccc)\b)*, в основном тот же шаблон, но с \s+ впереди и заключенный в *. И тогда нам нужно, чтобы строка где-то заканчивалась. Это делается с помощью знака доллара $.

Для регулярного выражения 2:

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

//var re = /^(?=.*?\baaa\b)(?!.*?\baaa\b.*?\baaa\b)(?=.*?\bbbb\b)(?!.*?\bbbb\b.*?\bbbb\b)(?=.*?\bccc\b)(?!.*?\bccc\b.*?\bccc\b)\b(?:aaa|bbb|ccc)\b(?:\s+\b(?:aaa|bbb|ccc)\b)*$/;
// optimized version, see comments
var re = /^(?=.*?\baaa\b)(?=.*?\bbbb\b)(?=.*?\bccc\b)(?!.*?\b(\w+)\b.*?\b\1\b)\b(?:aaa|bbb|ccc)\b(?: +\b(?:aaa|bbb|ccc)\b)*$/;
var res = document.getElementById('result');
res.innerText += re.test('aaa ccc bbb');
res.innerText += ', ' + re.test('aaa ccc ddd');
res.innerText += ', ' + re.test('aaa bbb aaa');
res.innerText += ', ' + re.test('aaa ccc bbb ccc');
<div id = "result"></div>

Во-первых, у нас есть положительный прогноз (?=.*?\bword\b), чтобы увидеть, что это слово существует. Мы следуем этому с помощью отрицательного просмотра (?!.*?\baaa\b.*?\baaa\b), чтобы увидеть, что слово не существует несколько раз. Повторить для всех слов. Престо!

Обновлять: вместо того, чтобы проверять, что определенные слова не повторяются, мы также можем проверить, НЕ повторяется ли слово, используя конструкцию (?!.*?\b(\w+)\b.*?\b\1\b). Это делает регулярное выражение более кратким. Спасибо @revo за указание на это.

Извините, мой опыт работы с регулярными выражениями основан на многолетней практике. Вам нужно познакомиться со своими инструментами, т. е. проверить ВСЕ доступные конструкции, особенно возможности отрицания, используя либо отрицательные классы символов [^abcd], либо отрицательные утверждения с опережением/просмотром назад (в примере). Они очень мощные, но их нужно хорошо понимать, чтобы они функционировали должным образом. После этого собираем вещи вместе и немного проб и ошибок :-)

Christoph Herold 12.03.2019 09:40

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

shajji 12.03.2019 09:46

Вы можете удалить все эти негативные прогнозы в пользу (?!.*?\b(\w+)\b.*?\b\1\b)

revo 12.03.2019 09:51

и вы не должны использовать \s, иначе это испортит многострочные входные строки.

revo 12.03.2019 09:53

@revo: AFAI понял вопрос, мы ищем конкретные слова, а не просто слова. Кроме того, \s также должен фиксировать перевод строки и возврат каретки, чтобы ничего не испортить. То есть, если мы допустим CR и LF в качестве разделителей.

Christoph Herold 12.03.2019 09:56

А, хорошо, теперь я понял. Сначала ищите все конкретные слова, а затем дважды проверяйте, что слово НЕ существует. Да, хорошая оптимизация.

Christoph Herold 12.03.2019 09:57

Вы сопоставляете входную строку только с aaa, bbb и ccc вне поиска, поэтому это означает, что мы не ищем другие слова, поэтому короткий просмотр делает свою работу. Кроме того, .*? не выходит за пределы новой строки, но позже вы говорите, что новая строка может соответствовать \s.

revo 12.03.2019 09:59

Посмотрите здесь, чтобы понять, как ваше регулярное выражение ведет себя с многострочными входными строками regex101.com/r/5EMjEN/1

revo 12.03.2019 10:01

Приказы осмотра вообще не важны. Это (?=.*\baaa\b)(?=.*\bbbb\b)(?=.*\bccc\b)(?!.*?\b(\w+)\b.*?\1), но может быть (?!.*?\b(\w+)\b.*?\1)(?=.*\baaa\b)(?=.*\bbbb\b)(?=.*\bccc\b)‌​.

revo 12.03.2019 10:03

Да, я знаю об этом. Мы должны добавить модификатор s в конце регулярного выражения, чтобы избавиться от этого несоответствия.

Christoph Herold 12.03.2019 10:03

Нет, вы должны исключить новые строки из сопоставления.

revo 12.03.2019 10:04

Ах, только что узнал, что JS не предлагает модификатор s, так что да, мы должны исключить новую строку из сопоставления.

Christoph Herold 12.03.2019 10:06

Начиная с ECMAScript 2018 добавлен модификатор s. Однако вы можете использовать [\s\S] вместо . в любое время, чтобы добиться такого же поведения.

revo 12.03.2019 10:08

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

shajji 12.03.2019 10:08

Это зависит от вашего варианта использования. Вам нужны дубликаты или нет?

Christoph Herold 12.03.2019 10:09

@shajji Первое регулярное выражение также допускает повторения, хотя не должно regex101.com/r/K63tsv/1

revo 12.03.2019 10:09

Но это был именно вопрос ОП: первый ДОЛЖЕН разрешать повторения, а второй - нет. Так что, в зависимости от того, что вам нужно, используйте тот или иной.

Christoph Herold 12.03.2019 10:10

Я обновил ответ, чтобы разрешить только пробел в качестве разделителя, так как это кажется целью.

Christoph Herold 12.03.2019 10:11

наконец, я понимаю оба регулярных выражения, это очищает мою положительную/отрицательную концепцию просмотра вперед. спасибо вам обоим :) Кристоф и @revo

shajji 13.03.2019 05:48

Без повторений regex101

^(?:(aaa|bbb|ccc)(?!.*?\b\1) ?\b){3}$

И с повторением regex101

^(?=.*?\baaa)(?=.*?\bbbb)(?=.*?\bccc)(?:(aaa|bbb|ccc) ?\b)+$

Еще две идеи. Объяснение регулярного выражения в regex101 с правой стороны.

Другие вопросы по теме