Я пытаюсь токенизировать выражение по следующим правилам:
Разделителями являются '}}' и '{{'
Строки между разделителями должны быть неповрежденными (исключая отдельные пробелы, которые отбрасываются (может быть сделано в парсере)
Разделители могут быть встроены, и порядок должен быть сохранен
Отдельные вхождения '{' и '}' должны быть оставлены нетронутыми и не использоваться в качестве разделителей (см. Последнее испытание).
В результате не должно быть пустых строк (это можно сделать в парсере)
Пара исключений (помеченных в скобках) может быть сделана последующей обработкой (правильного) результата в разборе. Результат будет передан парсеру рекурсивного спуска.
Вот несколько испытаний, которые не проходят модульные тесты, которые я включил. Функция find_all
наиболее близка к совпадению, но все же удается отбросить некоторые части. Я не использую re.split()
в приведенном ниже коде (он будет содержать пустые строки), но я попробовал его без удачи. Я надеюсь, что регулярное выражение будет работать, чтобы избежать сканирования строк за символом в моем коде.
def tokenize_search(line):
token_pat = re.compile(r'({{)([^{(?!{)]*|[^}(?!})]*)(}})')
tokens = re.search(token_pat, line).groups()
return list (tokens)
def tokenize_findall(line):
token_pat = re.compile(r'({{)([^{(?!{)]*|[^}(?!})]*)(}})')
tokens = re.findall(token_pat, line)
return tokens
def check(a1, a2):
print(a1 == a2)
def main():
check(tokenize_search('{{}}'), ['{{', '}}'])
check(tokenize_search('aaa {{}}'), ['{{', '}}'])
check(tokenize_search('{{aaa}}'), ['{{', 'aaa', '}}'])
check(tokenize_search('{{aa}} {{bbb}}'), ['{{', 'aa', '}}', '{{', 'bbb', '}}'])
check(tokenize_search('{{aaa {{ bb }} }}'), ['{{', 'aaa ', '{{', ' bb ', '}}', '}}'])
check(tokenize_search('{{aa {{ bbb {{ c }} }} }}'), ['{{', 'aa ', '{{', ' bbb ', '{{', ' c ', '}}', '}}', '}}'])
check(tokenize_search('{{a{a}{{ b{b}b {{ c }} }} }}'), ['{{', 'a{a}', '{{', ' b{b}b ', '{{', ' c ', '}}', '}}', '}}'])
UPDATE
Спасибо Оливье за предоставленное решение. Я все еще надеюсь, что решение для регулярных выражений могло бы работать, если бы я мог лучше понять поиск регулярных выражений. Если я использую метод tokenize_finditer
, приведенный ниже, он проходит тесты, и все, что он делает, - заполняет группы skipped
промежуточными элементами (за исключением пространства, которое я мог бы постобработать, чтобы сделать код проще). Поэтому я надеюсь, что я смогу добавить выражение or
к регулярному выражению '({{)|(}})'
, которое говорит: `или получить любой символ, за которым следует любой символ, который не соответствует '}}' или '{{'. К сожалению, я не могу написать этот матч. Я видел примеры регулярных выражений, способных даже выполнять рекурсивное сопоставление, и поскольку это не рекурсивно, это звучит даже более выполнимо.
def tokenize_finditer(line):
token_pat = re.compile(r'({{)|(}})')
result = []
if re.search(token_pat, line):
prev = len(line)
for match in re.finditer(token_pat, line):
start, end = match.span()
if start > prev:
expr = line[prev:start]
if not expr.isspace():
result.append(expr)
prev = end
result.append(match.group())
return result