2015-11-19 2 views
4

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

CustomerID:1111, 

text1 

CustomerID:2222, 

text2 

CustomerID:3333, 

text3 

CustomerID:4444, 

text4 

CustomerID:5555, 

text5 

Каждый текст имеет несколько строк.

Я хочу сохранить идентификатор клиента и текст для каждого идентификатора в кортежах (например, (1111, text1), (2222, text2) и т. Д.).

Во-первых, я использую выражение ниже:

re.findall('CustomerID:(\d+)(.*?)CustomerID:', rawtxt, re.DOTALL) 

Однако, я только получаю (1111, text1), (3333, text3), (5555, text5) .....

ответ

2
re.findall(r'CustomerID:(\d+),\s*(.*?)\s*(?=CustomerID:|$)', rawtxt, re.DOTALL) 

FindAll возвращает только groups. использовать lookahead для остановки non greedy quantifier.Its также предложил использовать r или raw режима, чтобы указать ваш regexes.If вы не используете lookahead затем customerid на следующий матч будет потребляться и поэтому следующий матч не present.Overlapping матчей должны быть удалено с помощью lookahead, которые не потребляют string

+0

Какова функция 're.DOTALL' – SIslam

+1

@SIslam '.' по умолчанию не соответствует' \ n' или 'newline'. С этим флагом он делает. Так что теперь'. * 'Будет соответствовать mulitline – vks

+0

Ah! здесь с и без 're.DOTALL' печатает то же самое! – SIslam

2

на самом деле не нужно регулярное выражение здесь:

>>> with open('file') as f: 
...  rawtxt = [i.strip() for i in f if i != '\n'] 
...  
>>> l = [] 
>>> for i in [rawtxt[i:i+2] for i in range(0, len(rawtxt), 2)]: 
...  l.append((i[0][11:-1], i[1])) 
...  
... 
>>> l 
[('1111', 'text1'), ('2222', 'text2'), ('3333', 'text3'), ('4444', 'text4'), ('5 
555', 'text5')] 
>>> 

Если вам нужно 1111, 2222 и т.д. быть ИНТ, используйте l.append((int(i[0][11:-1]), i[1])) вместо l.append((i[0][11:-1], i[1])).

+1

Можно сделать, если формат данных исправлен :) – vks

1

Дано:

>>> txt='''\ 
... CustomerID:1111, 
... 
... text1 
... 
... CustomerID:2222, 
... 
... text2 
... 
... CustomerID:3333, 
... 
... text3 
... 
... CustomerID:4444, 
... 
... text4 
... 
... CustomerID:5555, 
... 
... text5''' 

Вы можете сделать:

>>> [re.findall(r'^(\d+),\s+(.+)', block) for block in txt.split('CustomerID:') if block] 
[[('1111', 'text1')], [('2222', 'text2')], [('3333', 'text3')], [('4444', 'text4')], [('5555', 'text5')]] 

Если это многострочный текст, вы можете сделать:

>>> [re.findall(r'^(\d+),\s+([\s\S]+)', block) for block in txt.split('CustomerID:') if block] 
[[('1111', 'text1\n\n')], [('2222', 'text2\n\n')], [('3333', 'text3\n\n')], [('4444', 'text4\n\n')], [('5555', 'text5')]] 
1

Другой простой может быть-

>>>re.findall(r'(\b\d+\b),\s*(\btext\d+\b)', rawtxt) 
>>>[('1111', 'text1'), ('2222', 'text2'), ('3333', 'text3'), ('4444', 'text4'), ('5555', 'text5')] 

Edit- При необходимости (в худшую сторону упорядочивания данных) использовать filter

filter(lambda x: len(x)>1,re.findall(r'(\b\d+\b),\s*(\btext\d+\b)', rawtxt)) 

SEE DEMO Live Demo

0

re.findall не является лучшим инструментом для этого, так как регулярное выражение всегда жадны и будет пытаться сожрать все последующие идентификаторы клиента с текстом.

Инструмент, созданный для этого, является re.split. Скобки фиксируют номер идентификатора и фильтруют «CustomerID». Вторая линия сшивает маркер кортежей так, как вы хотели:

toks = re.split(r'CustomerID:(\d{4}),\n', t) 
zip(toks[1::2],toks[2::2]) 

EDIT: исправлен индекс в почтовом индексе(). Выход проб после коррекции:

[('1111', 'text1\n'), 
('2222', 'text2\n'), 
('3333', 'text3\n'), 
('4444', 'text4\n'), 
('5555', 'text5')] 
+0

Это не то, что хочет OP, ваше выражение возвращает '[('1111', '2222'), ('2222', '3333'), ('3333', '4444'), ('4444', '5555')] ' – SIslam

+0

@SIslam ... toks [2 :: 2] вместо токов [3 :: 2]. Я исправлю это – Muposat

Смежные вопросы