многострочное сопоставление с образцом в python - PullRequest
0 голосов
/ 27 апреля 2010

Периодическое компьютерное сообщение (упрощенно):

Hello user123,

- (604)7080900
- 152
- minutes

Regards

Используя python, как извлечь «(604) 7080900», «152», «минуты» (т. Е. Любой текст, следующий за начальным шаблоном "- ") между двумя пустыми строками (пустая строка - \n\n после «Здравствуйте, user123» и \n\n перед «С уважением»). Еще лучше, если список строк результата хранится в массиве. Спасибо!

edit: количество строк между двумя пустыми строками не фиксировано.

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

, например

hello

- x1
- x2
- x3

- x4

- x6
morning
- x7

world

x1 x2 x3 хороши, так как все строки окружены 2 пустыми строками, x4 также хорош по той же причине. x6 не годится, потому что за ним нет пустой строки, x7 не годится, так как перед ним нет пробела. х2 - это хорошо (не так, как х6, х7), потому что линия впереди - это хорошая линия, а линия, следующая за ней, также хороша.

эти условия могут быть неясны, когда я разместил вопрос:

a continuous of good lines between 2 empty lines

good line must have leading "- "
good line must follow an empty line or follow another good line
good line must be followed by an empty line or followed by another good line

спасибо

Ответы [ 4 ]

4 голосов
/ 27 апреля 2010
>>> import re
>>>
>>> x="""Hello user123,
...
... - (604)7080900
... - 152
... - minutes
...
... Regards
... """
>>>
>>> re.findall("\n+\n-\s*(.*)\n-\s*(.*)\n-\s*(minutes)\s*\n\n+",x)
[('(604)7080900', '152', 'minutes')]
>>>
3 голосов
/ 27 апреля 2010

Самый простой подход - пройти по этим строкам (при условии, что у вас есть список строк или файл, или разбить строку на список строк), пока вы не увидите строку, которая просто '\n', а затем проверить строка начинается с '- ' (с использованием строкового метода startswith) и обрезает его, сохраняя результат, пока не найдете другую пустую строку. Например:

# if you have a single string, split it into lines.
L = s.splitlines()
# if you (now) have a list of lines, grab an iterator so we can continue
# iteration where it left off.
it = iter(L)
# Alternatively, if you have a file, just use that directly.
it = open(....)

# Find the first empty line:
for line in it:
    # Treat lines of just whitespace as empty lines too. If you don't want
    # that, do 'if line == ""'.
    if not line.strip():
        break
# Now starts data.
for line in it:
    if not line.rstrip():
        # End of data.
        break
    if line.startswith('- '):
        data.append(line[:2].rstrip())
    else:
        # misformed data?
        raise ValueError, "misformed line %r" % (line,)

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

def getblocks(L):
    # The list of good blocks (as lists of lines.) You can also make this
    # a flat list if you prefer.
    data = []
    # The list of good lines encountered in the current block
    # (but the block may still become bad.)
    block = []
    # Whether the current block is bad.
    bad = 1
    for line in L:
        # Not in a 'good' block, and encountering the block separator.
        if bad and not line.rstrip():
            bad = 0
            block = []
            continue
        # In a 'good' block and encountering the block separator.
        if not bad and not line.rstrip():
            # Save 'good' data. Or, if you want a flat list of lines,
            # use 'extend' instead of 'append' (also below.)
            data.append(block)
            block = []
            continue
        if not bad and line.startswith('- '):
            # A good line in a 'good' (not 'bad' yet) block; save the line,
            # minus
            # '- ' prefix and trailing whitespace.
            block.append(line[2:].rstrip())
            continue
        else:
            # A 'bad' line, invalidating the current block.
            bad = 1
    # Don't forget to handle the last block, if it's good
    # (and if you want to handle the last block.)
    if not bad and block:
        data.append(block)
    return data

И вот оно в действии:

>>> L = """hello
...
... - x1
... - x2
... - x3
...
... - x4
...
... - x6
... morning
... - x7
...
... world""".splitlines()
>>> print getblocks(L)
[['x1', 'x2', 'x3'], ['x4']]
1 голос
/ 27 апреля 2010
l = """Hello user123,

- (604)7080900
- 152
- minutes

Regards  

Hello user124,

- (604)8576576
- 345
- minutes
- seconds
- bla

Regards"""

сделать это:

result = []
for data in s.split('Regards'): 
    result.append([v.strip() for v in data.split('-')[1:]])
del result[-1] # remove empty list at end

и иметь это:

>>> result
[['(604)7080900', '152', 'minutes'],
['(604)8576576', '345', 'minutes', 'seconds', 'bla']]
1 голос
/ 27 апреля 2010
>>> s = """Hello user123,

- (604)7080900
- 152
- minutes

Regards
"""
>>> import re
>>> re.findall(r'^- (.*)', s, re.M)
['(604)7080900', '152', 'minutes']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...