Регулярные выражения: обеспечение b не происходит между a и c

Здесь что-то я пытаюсь делать с регулярными выражениями, и я не могу понять, как это сделать. У меня большой файл, а строки abc, 123 и xyz, которые появляются несколько раз по всему файлу.

Я хочу, чтобы регулярное выражение соответствовало подстроке большого файла, который начинается с abc, содержит 123 где-то посередине, заканчивается xyz, , и нет других экземпляров abc или xyz в подстроке, кроме начала и конца.

Возможно ли это с регулярными выражениями?

Ответ 1

Вам нужен умеренный жадный токен:

abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz

Смотрите демонстрацию regex

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

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

Сведения о шаблоне:

  • abc - соответствие abc
  • (?:(?!abc|xyz|123).)* - сопоставить любой символ, который не является отправной точкой для последовательностей символов abc, xyz или 123
  • 123 - буквальная строка 123
  • (?:(?!abc|xyz).)* - любой символ, который не является отправной точкой для последовательностей символов abc или xyz
  • xyz - конечная подстрока xyz

См. диаграмму ниже (если используется re.S, . будет означать AnyChar):

введите описание изображения здесь

См. Демо-версия Python:

import re
p = re.compile(r'abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz', re.DOTALL)
s = "abc 123 xyz\nabc abc 123 xyz\nabc text 123 xyz\nabc text xyz xyz"
print(p.findall(s))
// => ['abc 123 xyz', 'abc 123 xyz', 'abc text 123 xyz']

Ответ 2

comment hvd вполне уместен, и это просто пример. В SQL, например, я думаю, что было бы более понятно:

where val like 'abc%123%xyz' and
      val not like 'abc%abc%' and
      val not like '%xyz%xyz'

Я предполагаю, что нечто подобное очень просто сделать в других средах.

Ответ 3

Вы можете использовать lookaround.

/^abc(?!.*abc).*123.*(?<!xyz.*)xyz$/g

(Я не тестировал его.)

Ответ 4

Используя PCRE, решение будет:

Это использование флага m. Если вы хотите проверить только с начала и конца строки, добавьте ^ и $ в начало и конец соответственно

abc(?!.*(abc|xyz).*123).*123(?!.*(abc|xyz).*xyz).*xyz

Regular expression visualization

Демоверсия Debuggex