两个字符串python之间的正则表达式文本
我有一些这样的文字:两个字符串python之间的正则表达式文本,python,regex,Python,Regex,我有一些这样的文字: CustomerID:1111, text1 CustomerID:2222, text2 CustomerID:3333, text3 CustomerID:4444, text4 CustomerID:5555, text5 每个文本有多行 我想将客户id和每个id的文本存储在元组中(例如(1111,text1),(2222,text2),等等) 首先,我使用下面的表达式: re.findall('CustomerID:(\d+)(.*?)Custo
CustomerID:1111,
text1
CustomerID:2222,
text2
CustomerID:3333,
text3
CustomerID:4444,
text4
CustomerID:5555,
text5
每个文本有多行
我想将客户id和每个id的文本存储在元组中(例如(1111,text1)
,(2222,text2)
,等等)
首先,我使用下面的表达式:
re.findall('CustomerID:(\d+)(.*?)CustomerID:', rawtxt, re.DOTALL)
然而,我只得到(1111,text1)
,(3333,text3)
,(5555,text5)
re.findall(r'CustomerID:(\d+),\s*(.*?)\s*(?=CustomerID:|$)', rawtxt, re.DOTALL)
Findall只返回
组
。使用lookahead
停止non-greedy
量词。还建议使用r
或raw
模式指定正则表达式。如果不使用lookahead
,则下一个匹配的customerid
将被消耗,因此下一个匹配将不存在。必须通过使用不使用字符串的lookahead
实际上不需要正则表达式:
>>> 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
等为int,请使用l.append((int(i[0][11:-1]),i[1])
而不是l.append((i[0][11:-1],i[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')]]
如果是多行文字,则可以执行以下操作:
>>> [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')]]
另一个简单的可能是-
>>>re.findall(r'(\b\d+\b),\s*(\btext\d+\b)', rawtxt)
>>>[('1111', 'text1'), ('2222', 'text2'), ('3333', 'text3'), ('4444', 'text4'), ('5555', 'text5')]
编辑-
如果需要(对于顺序更差的数据),请使用filter
filter(lambda x: len(x)>1,re.findall(r'(\b\d+\b),\s*(\btext\d+\b)', rawtxt))
见演示
re.findall并不是最好的工具,因为regex总是贪婪的,会试图用文本吞掉所有后续的customerID
为此实际创建的工具是重新拆分。括号捕获id号并过滤掉“CustomerID”。第二行按您希望的方式将标记缝合到元组中:
toks = re.split(r'CustomerID:(\d{4}),\n', t)
zip(toks[1::2],toks[2::2])
编辑:已更正zip()中的索引。校正后的样本输出:
[('1111', 'text1\n'),
('2222', 'text2\n'),
('3333', 'text3\n'),
('4444', 'text4\n'),
('5555', 'text5')]
re.DOTALL
@SIslam
的功能是什么?默认值与\n
或换行符
不匹配。有了此标志,它就匹配了。因此现在*
将匹配多行符!这里有和没有re.DOTALL
打印的都一样@因为我们用\s
覆盖\n
或新行
,所以在这种情况下,我们是否需要re.DOTALL
?感谢这不是OP想要的,您的表达式返回[('1111','2222'),('2222','3333'),('3333','4444'),('4444','5555')]
@SIslam。。。toks[2::2]而不是toks[3::2]。我会改正的