我有一个数据集,其中包含由|分隔的tag = value对行(\ X01)。以下是单行示例:
120 = 3 | 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 | 100 = 087 | \ n
我想要做的是使用正则表达式捕获每个重复块 - 每个重复块以标记162开头,以标记4562结束,中间标记也始终相同 - 并将其放在列表中。
以上示例的输出应如下:
['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。
感谢您的帮助。
答案 0 :(得分:2)
使用一点正则表达式,然后使用str.replace()
:
>>> result = re.findall(r'\b162=\d+(?:\|\d+=\d+)+?\|4562=\d+', line)
>>> result = [l.replace('|', ' ') for l in result]
>>> print(result)
['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']
正则表达式验证问题中描述的格式。然后str.replace
有助于将|
转换为单个空格' '
。
正则表达式:\b162=\d+(?:\|\d+=\d+)+?\|4562=\d+
\b162
匹配字边界,后跟162,以便2162等不匹配=\d+
匹配等于=
,后跟至少一个数字(?:\|\d+=\d+)+?
是一个非捕获组,允许任意数量的|
后跟数字=
,数字,格式为| N = N \|4562=\d+
匹配最后一部分,即|
后跟4562,=
和数字答案 1 :(得分:1)
纯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层上运行,而上面的大部分代码都被解释为......
更新 - 但是,我们可以在程序上仍然击败regex
,考虑一下:
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 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