2017-02-22 22 views
0

Я пытаюсь написать шаблон регулярного выражения, который будет соответствовать любой строке, содержащей слова «28», «бонус» и «день».Regex: список совпадений без повторного использования ранее согласованных слов

На данный момент я пришел с этим:

(bonus|(days|day)|(28th|28)|twenty[ \-\t]*(eighth|eight))[ \ta-z]*(bonus|days|day|(28th|28)|twenty[ \-\t]*(eighth|eight))[ \ta-z]*(bonus|days|day|(28th|28)|twenty[ \-\t]*(eighth|eight)) 

Вы можете просмотреть результаты здесь: https://regex101.com/r/oOcGqk/8

Проблемы я имею что любое слово может быть использованы несколько раз, и до сих пор быть согласованным. Например: «Бонус дня дня», «Бонусный бонус». Как я могу исключить строки, которые используют любое из этих слов («28», «бонус», «день») более одного раза?

+0

Ваше регулярное выражение очень сложное, правила, которые вам нужно выполнить, действительно сложны (в первом предложении предлагается иное)? Не могли бы вы описать, какие именно правила соответствуют строке? Скорее всего, это можно сделать проще и без проблемы дублирования, с которой вы сталкиваетесь. –

+0

@pietzcker Правила, которыми должно следовать регулярное выражение, следующие: 1) Сопоставьте любую строку, содержащую «28», «бонус» и «день» 2) Не сопоставляйте ни одной строке, содержащей любое из этих слов, более одного раза. например. «бонус дневного дня» или «бонусный бонусный бонус» – colio303

+0

Также: Какой аромат регулярного выражения? Я надеюсь, что это не JavaScript, иначе решение, о котором я думаю, не будет работать ... –

ответ

1

Я думаю this регулярное выражение expresion это решение:

(?=.*bonus)(?=.*day)(?=.*28|twenty\s*-?\s*eight).* 
+0

Это не исключает нескольких совпадений одного и того же слова. –

+0

@TimPietzcker «любая строка, содержащая« 28 »,« бонус »и« день »» ... содержащая! = С exacly one –

+0

См. Последнее предложение вопроса: «Как я могу исключить строки, которые используют любой из этих слова («28», «бонус», «день») более одного раза? » –

1

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

^  # Start of string 
(?=(?:(?!bonus).)*bonus()(?:(?!bonus).)*$) 
# Explanation: This lookahead assertion makes sure that "bonus" occurs exactly once 
# in the string. It doesn't actually match any text, it just "looks ahead" to see if 
# that condition is met. However, it contains an empty capturing group "()" that only 
# participates in the match if the lookahead assertion succeeds. We can check this later. 
(?=(?:(?!days?).)*days?()(?:(?!days?).)*$) 
(?=(?:(?!28(?:th)?|twenty-eighth?).)*(?:28(?:th)?|twenty-eighth?)()(?:(?!28(?:th)?|twenty-eighth?).)*$) 
[\w\s]* # Match a string that only contains alnum character or whitespace 
\1\2\3 # Assert that all three words participated in the match 
$  # End of string. 

Вы можете проверить это here

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

Просто в качестве отправной точки: Ниже регулярное выражение будет соответствовать строки, содержащие bonus, days и 28 ровно один раз, но это позволяет им только в порядке «bonus, days и 28» или «days, bonus и 28». Вам нужно будет добавить остальные четыре перестановки, чтобы получить полное регулярное выражение (и полный беспорядок). Делайте это программно, а не с регулярным выражением.

^(?:(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*bonus(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*days?(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*(?:28(?:th)?|twenty-eighth?)(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*|(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*days?(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*bonus(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*(?:28(?:th)?|twenty-eighth?)(?:(?!bonus|days?|28(?:th)?|twenty-eighth?).)*)$ 

Протестируйте его here. Вы были предупреждены.

+0

Это не очень масштабируемое решение. –

+0

Моя точка точно. –

 Смежные вопросы

  • Нет связанных вопросов^_^