Мое регулярное выражение в Python не повторяется должным образом - PullRequest
2 голосов
/ 05 июня 2009

Я предполагаю захватить все внутри тега и следующих строк после него, но он должен остановиться в следующий раз, когда встретится скобка. Что я делаю не так?

import re #regex

regex = re.compile(r"""
         ^                    # Must start in a newline first
         \[\b(.*)\b\]         # Get what's enclosed in brackets 
         \n                   # only capture bracket if a newline is next
         (\b(?:.|\s)*(?!\[))  # should read: anyword that doesn't precede a bracket
       """, re.MULTILINE | re.VERBOSE)

haystack = """
[tab1]
this is captured
but this is suppose to be captured too!
@[this should be taken though as this is in the content]

[tab2]
help me
write a better RE
"""
m = regex.findall(haystack)
print m

что я пытаюсь получить:
[('tab1', 'это захвачено \ n, но это тоже должно быть захвачено! \ N @ [это следует принимать, хотя это в содержании] \ n', '[tab2]', ' помогите мне \ nпишите лучше RE \ n ')]

редактирование:

regex = re.compile(r"""
             ^           # Must start in a newline first
             \[(.*?)\]   # Get what's enclosed in brackets 
             \n          # only capture bracket if a newline is next
             ([^\[]*)    # stop reading at opening bracket
        """, re.MULTILINE | re.VERBOSE)

это похоже на работу, но это также сокращает скобки внутри контента.

Ответы [ 3 ]

3 голосов
/ 06 июня 2009

Прежде всего, почему регулярное выражение, если вы пытаетесь разобрать? Как вы можете видеть, вы не можете найти источник проблемы самостоятельно, потому что регулярное выражение не дает обратной связи. Также у вас нет рекурсии в этом RE.

Сделай свою жизнь проще:

def ini_parse(src):
   in_block = None
   contents = {}
   for line in src.split("\n"):
      if line.startswith('[') and line.endswith(']'):
         in_block = line[1:len(line)-1]
         contents[in_block] = ""
      elif in_block is not None:
         contents[in_block] += line + "\n"
      elif line.strip() != "":
         raise Exception("content out of block")
   return contents

Вы получаете обработку ошибок с исключениями и возможность отладки выполнения в качестве бонуса. Также вы получаете словарь в результате и можете обрабатывать дубликаты разделов при обработке. Мой результат:

{'tab2': 'help me\nwrite a better RE\n\n',
 'tab1': 'this is captured\nbut this is suppose to be captured too!\n@[this should be taken though as this is in the content]\n\n'}

В наши дни RE сильно злоупотребляют ...

3 голосов
/ 05 июня 2009

Python regex не поддерживает рекурсию afaik.

РЕДАКТИРОВАТЬ: но в вашем случае это будет работать:

regex = re.compile(r"""
         ^           # Must start in a newline first
         \[(.*?)\]   # Get what's enclosed in brackets 
         \n          # only capture bracket if a newline is next
         ([^\[]*)    # stop reading at opening bracket
    """, re.MULTILINE | re.VERBOSE)

РЕДАКТИРОВАТЬ 2: да, это не работает должным образом.

import re

regex = re.compile(r"""
    (?:^|\n)\[             # tag's opening bracket  
        ([^\]\n]*)         # 1. text between brackets
    \]\n                   # tag's closing bracket
    (.*?)                  # 2. text between the tags
    (?=\n\[[^\]\n]*\]\n|$) # until tag or end of string but don't consume it
    """, re.DOTALL | re.VERBOSE)

haystack = """[tag1]
this is captured [not a tag[
but this is suppose to be captured too!
[another non-tag

[tag2]
help me
write a better RE[[[]
"""

print regex.findall(haystack)

Хотя я согласен с viraptor. Regex - это круто, но вы не можете проверить ваш файл на наличие ошибок. Гибрид что ли? : P

tag_re = re.compile(r'^\[([^\]\n]*)\]$', re.MULTILINE)
tags = list(tag_re.finditer(haystack))

result = {}
for (mo1, mo2) in zip(tags[:-1], tags[1:]):
    result[mo1.group(1)] = haystack[mo1.end(1)+1:mo2.start(1)-1].strip()
result[mo2.group(1)] = haystack[mo2.end(1)+1:].strip()

print result

РЕДАКТИРОВАТЬ 3: Это потому, что символ ^ означает отрицательное совпадение только внутри [^squarebrackets]. В любом другом месте это означает начало строки (или начало строки с re.MULTILINE). Нет хорошего способа найти отрицательное соответствие в регулярном выражении, только символ.

2 голосов
/ 05 июня 2009

Делает ли это то, что вы хотите?

regex = re.compile(r"""
         ^                      # Must start in a newline first
         \[\b(.*)\b\]           # Get what's enclosed in brackets 
         \n                     # only capture bracket if a newline is next
         ([^[]*)
       """, re.MULTILINE | re.VERBOSE)

Это дает список кортежей (один 2-кортеж на матч). Если вы хотите сплющенный кортеж, вы можете написать:

m = sum(regex.findall(haystack), ())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...