Python 重复标记的正则表达式=值块
我有一个数据集,其中包含由|(\x01)分隔的标记=值对行。下面是一个单线示例: 120=3 3 124; 162=0 0 0 0 0 0 0 0 0 0 0 | 162=3 0 0 0 0=3 3 | 162=3 0 0 0 0 0 0 0 0=3 3 3 | 162=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 162=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0=12 12444 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场\\\\| 10 10 10=10 10 10 10 10 10 10=10 10 10 10 10 10 10 10 10=3=3 \\\\\\|;=2 | 105=1 | 4562=10 | 100=087 | \n 我想做的是使用正则表达式捕获每个重复块——每个块以标记162开始,以标记4562结束,中间的标记也总是相同的——并将其放置在列表中 上述示例的输出应如下所示:Python 重复标记的正则表达式=值块,python,regex,Python,Regex,我有一个数据集,其中包含由|(\x01)分隔的标记=值对行。下面是一个单线示例: 120=3 3 124; 162=0 0 0 0 0 0 0 0 0 0 0 | 162=3 0 0 0 0=3 3 | 162=3 0 0 0 0 0 0 0 0=3 3 3 | 162=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 162=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0=12 12444 4 4 4 4 4 4 4 4 4 4 4 4 4 4
['162=0 181=1 72=24842 23=125 40=119 155=2321 130=3 105=1 4562=1',
'162=2 181=1 72=24842 23=125 40=120 155=2322 130=5 105=1 4562=2',
'162=0 181=1 72=24842 23=125 40=121 155=2326 130=2 105=1 4562=10']
我尝试了以下表达式的变体:
re.findall("(?:^|\x01)(162)=(.*?)(?=\x01)", line)
它正确地捕获了单个tag=value对,但是我还没有找到正确的表达式来将它们“粘合”在一起,以便获得上面描述的输出
请注意,每行都以一个标记开始,该标记通知我们包含的重复块的数量(1到N)。在这种特殊情况下,从标记120=3可以看出,它是3
谢谢您的帮助。使用一点正则表达式,然后使用str.replace(): 正则表达式验证问题中描述的格式。然后
str.replace
帮助将|
转换为单个空格'
正则表达式:\b162=\d+(?:\\\\\d+=\d+?\\\\\\\4562=\d+
匹配单词边界,后跟162,因此2162等不匹配\b162
匹配相等的=\d+
,后跟至少一个数字=
是一个非捕获组,允许任何数量的(?:\\\\\\d+=\d+?
后跟数字,
,数字即格式N=N=
匹配最后一部分,即\\\\4562=\d+
\/code>后跟4562、
和数字=
纯Python解决方案,无需正则表达式:
def parse_data(data):
result, current = [], [] # storage for our final result and current sublist
pairs = data.split("|") # lets first turn everything to key-value pairs
for pair in pairs:
if current or pair[:4] == "162=":
current.append(pair) # add to the current sublist
if pair[:5] == "4562=": # end tag, finalize the block
result.append(current) # add the sublist to our main result
current = [] # reinitialize sublist
return [" ".join(current) for current in result] # finally, space separate the pairs
parsed = parse_data(line)
# ['162=0 181=1 72=24842 23=125 40=119 155=2321 130=3 105=1 4562=1',
# '162=2 181=1 72=24842 23=125 40=120 155=2322 130=5 105=1 4562=2',
# '162=0 181=1 72=24842 23=125 40=121 155=2326 130=2 105=1 4562=10']
您可能应该使用regex
,但我想它在CPython上会更快。作为一个过程,“纯Python”比regex
引擎要做的事情要简单,但是regex
引擎运行在C层,而上面的大部分代码被解释为
<强>更新< /强> -但是,我们可以在程序上仍然跳过<代码>正则表达式>代码>,考虑这一个:
def parse_data_optimized(data):
result = [] # storage for our result
start = 0 # where to start searching our string
while True:
start = data.find("162=", start) # find the next 162 tag
end = data.find("4562=", start) # find the following 4562 tag
end = data.find("|", end) # find the key-value separator after the end tag
if start == -1 or end == -1: # if either search failed nothing more to search
break
result.append(data[start:end].replace("|", " ")) # slice's '|'->' ', add to result
start = end # set our next search to start from the end of the current one
return result # return the result
数据基准(使用degant的正则表达式进行比较,全部在CPython上):
这些数据看起来结构非常好,正则表达式似乎比简单地将其解析为python数据结构,然后按照您的意愿对其进行操作/格式化更为复杂和难以维护。有趣的是,您的优化版本确实比我的机器中的正则表达式快约50%。考虑到我正在处理的文件是巨大的,这种速度不是微不足道的。我对你们俩都投了赞成票,但看来我还是要用你们的解决方案!
def parse_data_optimized(data):
result = [] # storage for our result
start = 0 # where to start searching our string
while True:
start = data.find("162=", start) # find the next 162 tag
end = data.find("4562=", start) # find the following 4562 tag
end = data.find("|", end) # find the key-value separator after the end tag
if start == -1 or end == -1: # if either search failed nothing more to search
break
result.append(data[start:end].replace("|", " ")) # slice's '|'->' ', add to result
start = end # set our next search to start from the end of the current one
return result # return the result
# Python 3.5.1
zwer_1: 100,000 loops: 1.138 seconds
zwer_2: 100,000 loops: 0.515 seconds
regexp: 100,000 loops: 0.772 seconds
# Python 2.7.11
zwer_1: 100,000 loops: 0.833 seconds
zwer_2: 100,000 loops: 0.431 seconds
regexp: 100,000 loops: 0.763 seconds