复杂字符串分割,含有多个空格

3

我要解决的问题:

s = """X8 ifInDiscards=14308c X8 ifOutDiscards=133796c"""
s1 = """X3 InRXBytes=1257890123 X2 OutRXBytes=871625343 X5 OutRXBytes=71625343"""

让我们以上述两个字符串为例,我想把每个字符串分成不同的部分:
对于字符串s,
part1 = '''X8 ifInDiscards=14308c'''
part2 = '''X8 ifOutDiscards=133796c'''

针对字符串 s1,

part1 = '''X3 InRXBytes= 1257890123'''
part2 = '''X2 OutRXBytes= 871625343'''
part3 = '''X5 OutRXBytes= 71625343'''

因此,正如上面两个字符串示例所示,需要拆分的字符串格式为:
'''metric1=value1 metric2=value2....metricN=valueN'''

在上面的示例中,指标名称可以包含空格。

到目前为止,这是我尝试过但没有成功的内容:

>>> s = """X8 ifInDiscards=14308c X8 ifOutDiscards=133796c"""
>>>
>>>
>>>
>>> s.split('=')
['X8 ifInDiscards', '14308c X8 ifOutDiscards', '133796c']
>>>

问题是如何以最有效的方式拆分字符串?这里是我尝试过但没有成功的另一种方法:
>>> s 'X8 ifInDiscards=14308c X8 ifOutDiscards=133796c' 
>>> pattern = r'''[0-9a-zA-Z]?=[0-9a-zA-Z]? [0-9a-zA-Z]?=[0-9a-zA-Z]?''' 
>>> re.search(pattern, s) 

度量名称的长度可以是可变的,并且其中可以有多个空格...
最后编辑:这是最终的方法,似乎只适用于字符串“s”,而不适用于字符串“s1”,我想知道是否有更好的方法来解决这个问题:
>>> pattern = r'''([0-9a-zA-Z ].*?=[0-9a-zA-Z ].*?) ([0-9a-zA-Z ].*?=[0-9a-zA-Z ].*)'''
>>> s
'X8 ifInDiscards=14308c X8 ifOutDiscards=133796c'
>>> re.search(pattern, s).groups()
('X8 ifInDiscards=14308c', 'X8 ifOutDiscards=133796c')

你的正则表达式明确地寻找了恰好两个metric=value对,所以当然它不适用于s1。你可以将第一半分组并添加一个+而不是再次复制和粘贴它,或者你可以只使用第一半并使用re.findall而不是re.search - abarnert
此外,您可能希望允许除“='”以外的任何内容作为度量标准的一部分,而不仅仅是[0-9a-zA-Z ]。对于您现有的两个示例(其中没有超出该集合的字符),这不会有任何影响,但如果您有一个带有斜杠的度量标准,则您编写的正则表达式将无法匹配。 - abarnert
好的,我按照你的建议操作了,但它仍然返回相同的字符串:
pattern = r'''([0-9a-zA-Z ].?=[0-9a-zA-Z ].)+''' re.search(pattern, s1).group() 'X3 InRXBytes=1257890123 X2 OutRXBytes=871625343 X5 OutRXBytes=71625343'
- cog_n1t1v3
@ssheth:您在模式末尾添加的.*会导致第一组匹配第一个metric=value对和所有后续字符作为一个大匹配。如果您遵循其他建议,匹配除=以外的所有内容,并类似地匹配=另一侧的所有非空格内容,那么这将变得更加容易。 - abarnert
@ssheth:此外,使用re.search查找一个大组(无论如何)只会得到一个大字符串。您需要通过使用组将要作为单独值的部分分组。(而且您可能希望在=之前和之后分别使用单独的组;否则,在提取每个组后,您只需对每个组进行.split('=')操作。) - abarnert
显示剩余6条评论
2个回答

1
如果您查看s.split('=')的结果,您应该注意到每个值都是N-1,后跟度量N。而且,由于值不允许有空格,但矩阵名称允许有空格,因此如何将每个元素分成值和度量是清楚明确的,对吧?因此,只需将值列表向左移动一个位置并将其与度量列表一起压缩即可。只需记住边缘情况(第一个没有值,最后一个没有度量),您就可以很容易地编写它了。
如果您不理解压缩,也可以明确执行此操作:
d = {}
for i, part in enumerate(s1.split('=')):
    if i == 0:
        metric = part
    else:
        d[metric], _, metric = part.partition(' ')

但我强烈建议尝试找到简单的方法,如果遇到困难可以寻求帮助。


使用dict和partition方法是最简单的,也比使用正则表达式更好。非常感谢您的回答,我接受了。 - cog_n1t1v3

1
你在正确的轨道上。 re 是这项工作的正确工具。
不要尝试指定匹配组,反转您的模式并使用re.split - 将其视为强化版str.split
我将使用“lookaround”表达式 - 具体而言,我们希望在每个空格字符后面拆分一个单词,该单词不包含 = 标志。 否则称为由仅由字母数字字符组成的每个空格符后面的单词。 方便的是,我们可以非常简洁地表达这一点:\s(?=\w+\s)
s = """X8 ifInDiscards=14308c X8 ifOutDiscards=133796c"""
s1 = """X3 InRXBytes=1257890123 X2 OutRXBytes=871625343 X5 OutRXBytes=71625343"""

import re
pat = re.compile(r'\s(?=\w+\s)')

pat.split(s)
Out[17]: ['X8 ifInDiscards=14308c', 'X8 ifOutDiscards=133796c']

pat.split(s1)
Out[18]: 
['X3 InRXBytes=1257890123',
 'X2 OutRXBytes=871625343',
 'X5 OutRXBytes=71625343']

如果指标名称中没有空格,则该方法无效。它适用于我在问题中提供的两个示例,但是如果字符串如下所示,则无法正常工作:s1 ='''X3-InRXBytes=1257890123 X2_OutRXBytes=871625343'''。无论如何,感谢您提供正则表达式方法 :) - cog_n1t1v3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接