两个字符串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]。我会改正的