Головоломка с регулярными выражениями: сопоставьте шаблон, только если он находится между двумя $ $ без неопределенного поиска

#python #regex #regex-lookarounds #ultisnips

#python #регулярное выражение #регулярные выражения-поисковые системы #конечные ссылки

Вопрос:

Я пишу фрагмент для плагина Vim UltiSnips, который будет запускаться по шаблону регулярных выражений (как поддерживается Python 3). Чтобы избежать конфликтов, я хочу убедиться, что мой фрагмент запускается только тогда, когда содержится где-то внутри $ $___$ $. Обратите внимание, что шаблон триггера может содержать неопределенную строку впереди или позади него. Итак, в качестве примера я мог бы захотеть сопоставить все «a» в «$$ ccbbabbcc $$», но не «ccbbabbcc». Очевидно, это было бы тривиально, если бы я мог просто использовать неопределенный поиск сзади. Увы, я не могу, поскольку это не так .NET и vanilla Python этого не допустят. Существует ли стандартный способ реализации такого рода выражений? Обратите внимание, что я не смогу использовать какие-либо функции python. Выражение должно быть автономным триггером.

Комментарии:

1. Будет ли достаточно не жадного сопоставления: т. Е. $$.*?(a).*?$$ ?

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

3. Это могут быть разные фрагменты, каждый из которых запускается своим собственным соответствующим шаблоном X тогда и только тогда, когда этот X находится внутри двойных знаков доллара. Таким образом, шаблон X может использоваться для разных фрагментов, если он не найден внутри знаков доллара.

4. Пока ваша спецификация кажется неоднозначной. Если у вас есть три независимых фрагмента, соответствующие «a», «b» и «c», как следует анализировать следующие входные данные: $$-b-$$ a $$-c-$$ ?

5. Если у вас есть три независимых фрагмента, соответствующие «a», «b» и «c», нет однозначного способа проанализировать входные данные, подобного $$-b-$$ a $$-c-$$ . Вероятно, лучшим способом решить эту проблему было бы использовать разные символы для маркеров начала / конца. Таким образом, $@ - a - @$ сработало бы что-то вроде (т. Е. очень похоже на синтаксис для встроенных комментариев на некоторых языках: /* foo */ ).

Ответ №1:

Если то, что вы ищете, встречается только один раз между ‘$ $’, тогда:

 $$.*?(a)(?=.*?$$)
  

Это позволяет сопоставить все 3 a символа в следующем примере:

  1. $$) Соответствует ‘$ $’
  2. .*? Сопоставляет 0 или более символов без жадности
  3. (?=.*?$$) За строкой должно следовать 0 или более произвольных символов, за которыми следует ‘$ $’

Код:

 import re

s = "$$ccbbabbcc$$xxax$$bcaxay$$"

print(re.findall(r'$$.*?(a)(?=.*?$$)', s))
  

С принтами:

 ['a', 'a', 'a']
  

Комментарии:

1. Это приведет к сбою для входных строк типа $$-b-$$ a $$-c-$$ (т. Е. он сообщит о совпадении для a , когда этого не должно быть).

2. @ekhumoro Я согласен, что он найдет соответствие, но я за a с этим вводом, но я не уверен, почему этого не должно быть, когда OP указывает, что они ищут вхождение a между $$ и $$ . В любом случае, мое регулярное выражение основано на моей интерпретации вопроса, которая кажется довольно понятной с точки зрения английского языка.

3. Может показаться , что вопрос указывает на это, но в комментариях OP указано иное.

Ответ №2:

Должно сработать следующее:

 re.findall("${2}. ${2}", stuff)
  

Разбивка:

Ищет два ‘$’

 "${2}
  

Затем ищет один или несколько любых символов

 . 
  

Затем снова ищет два ‘$’

Комментарии:

1. Это приведет к совпадению ВСЕГО одного или нескольких символов между знаками доллара. Но я хочу сопоставить ‘a’ только между знаками долларов и игнорировать все остальные символы.

Ответ №3:

Я считаю, что это регулярное выражение будет соответствовать a внутри $$ :

 text = '$$ccbbabbcc$$ccbbabbcc'
re.findall('${2}.*(a).*${2}', text)
# prints
['a']
  

Альтернативно:

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

пример

 text = '$$ccbbabbcc$$ccbbabbcc'
search_string = 'a'
parts = re.findall('${2}. ${2}', text)
[p for p in parts if search_string in p]
# prints
['$$ccbbabbcc$$']
  

Комментарии:

1. Помните, что в примере 1) Я только хочу сопоставить ‘a’ внутри $$ ccbbabbcc $$ и 2) Я не могу использовать функции Python