Я плохо разбираюсь в регулярных выражениях, пытаюсь сделать 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).*$/
Спрашиваю с целью обучения, поэтому, пожалуйста, уточните это.
разрешены только пробелы, новая строка, табуляция.
Вы уверены, что между словами существуют новые строки?
k мой плохой, я думаю, я неправильно понял \b
@revo разрешены только пробелы и табуляции.
Пожалуйста, проверьте это regex101.com/r/Olu2kI/1
То, что вы можете использовать регулярное выражение, не означает, что вы должны это делать. 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");
@EricDuminil да, ты прав, мы можем решить это без регулярного выражения, но я изучаю регулярное выражение, как я описал в своем вопросе. просто хочу изучить новые способы написания регулярных выражений, чтобы в будущем я мог решить некоторые сложные проверки.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


зачем вам регулярное выражение для выполнения этой функции? вы можете легко добиться того, чего хотите, сначала разделив строки разделителем ",". Затем вы можете создать объект словаря со словами, которые вы ищете, поскольку ключи и значения по умолчанию равны -1.
Regex 2 можно получить, перебирая входные слова и проверяя, существуют ли они в качестве ключей в объекте словаря. Regex 1 может быть достигнут аналогичным образом, только когда ключ сопоставляется с входным словом, его значение затем будет изменено на 1, а при следующем посещении может быть возвращено ложное совпадение.
вы правы, каждая проверка может решить без регулярного выражения, но я намерен решить это с помощью регулярного выражения, если это возможно. пытаюсь выучить заранее регулярное выражение
Не используйте регулярное выражение для уникальности.
Но для отдельных слов в регулярном выражении вы можете использовать \b
Пример: /\b(word1|word2|word3)\b/
как насчет порядка?
@shajji это будет работать независимо от порядка. | (чередование) аналогично логическому ИЛИ
ты прав, но я собираюсь сделать кое-что другое, описанное в вопросе. хорошо спасибо за вашу помощь :).
Для регулярного выражения 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], либо отрицательные утверждения с опережением/просмотром назад (в примере). Они очень мощные, но их нужно хорошо понимать, чтобы они функционировали должным образом. После этого собираем вещи вместе и немного проб и ошибок :-)
ты прав. Мне нужно эффективно изучить отрицательные, обзорные утверждения, спасибо за вашу помощь.
Вы можете удалить все эти негативные прогнозы в пользу (?!.*?\b(\w+)\b.*?\b\1\b)
и вы не должны использовать \s, иначе это испортит многострочные входные строки.
@revo: AFAI понял вопрос, мы ищем конкретные слова, а не просто слова. Кроме того, \s также должен фиксировать перевод строки и возврат каретки, чтобы ничего не испортить. То есть, если мы допустим CR и LF в качестве разделителей.
А, хорошо, теперь я понял. Сначала ищите все конкретные слова, а затем дважды проверяйте, что слово НЕ существует. Да, хорошая оптимизация.
Вы сопоставляете входную строку только с aaa, bbb и ccc вне поиска, поэтому это означает, что мы не ищем другие слова, поэтому короткий просмотр делает свою работу. Кроме того, .*? не выходит за пределы новой строки, но позже вы говорите, что новая строка может соответствовать \s.
Посмотрите здесь, чтобы понять, как ваше регулярное выражение ведет себя с многострочными входными строками regex101.com/r/5EMjEN/1
Приказы осмотра вообще не важны. Это (?=.*\baaa\b)(?=.*\bbbb\b)(?=.*\bccc\b)(?!.*?\b(\w+)\b.*?\1), но может быть (?!.*?\b(\w+)\b.*?\1)(?=.*\baaa\b)(?=.*\bbbb\b)(?=.*\bccc\b).
Да, я знаю об этом. Мы должны добавить модификатор s в конце регулярного выражения, чтобы избавиться от этого несоответствия.
Нет, вы должны исключить новые строки из сопоставления.
Ах, только что узнал, что JS не предлагает модификатор s, так что да, мы должны исключить новую строку из сопоставления.
Начиная с ECMAScript 2018 добавлен модификатор s. Однако вы можете использовать [\s\S] вместо . в любое время, чтобы добиться такого же поведения.
Можете ли вы, ребята, сказать мне, какое регулярное выражение я должен использовать.
Это зависит от вашего варианта использования. Вам нужны дубликаты или нет?
@shajji Первое регулярное выражение также допускает повторения, хотя не должно regex101.com/r/K63tsv/1
Но это был именно вопрос ОП: первый ДОЛЖЕН разрешать повторения, а второй - нет. Так что, в зависимости от того, что вам нужно, используйте тот или иной.
Я обновил ответ, чтобы разрешить только пробел в качестве разделителя, так как это кажется целью.
наконец, я понимаю оба регулярных выражения, это очищает мою положительную/отрицательную концепцию просмотра вперед. спасибо вам обоим :) Кристоф и @revo
Итак, некоторые символы, такие как пробелы, могут существовать между словами? Что еще может быть там?