在python中使用正则表达式匹配可变数量的令牌出现次数

时间:2018-10-27 14:23:25

标签: python regex robotframework

我尝试多次匹配令牌,但是我只得到最后一次出现,我理解这是根据this answer的正常行为,但是我无法在那里找到解决方案在我的示例中。

我的文字看起来像这样:

&{dict1_name}=   key1=key1value   key2=key2value
&{dict2_name}=   key1=key1value

因此基本上是多行,每行都有一个起始字符串,空格,然后是可变数量的密钥对。如果您想知道这是哪里来的,那是我要转换为python变量文件的机器人框架变量文件。

我将每行进行迭代以匹配密钥对并从中构造一个python字典。

我当前的正则表达式模式是:

&{([^ ]+)}=[ ]{2,}(?:[ ]{2,}([^\s=]+)=([^\s=]+))+

如上所述,这可以正确地获取字典名称,但密钥对仅与最后一次匹配。如何获取返回包含("dict1_name","key1","key1value"..."keyn","keynvalue")的元组,以便随后可以对此进行迭代并像这样构造python字典:

dict1_name= {"key1": "key1value",..."keyn": "keynvalue"}

谢谢!

4 个答案:

答案 0 :(得分:1)

您可以将两个正则表达式用于名称,将另一个用于项目,将第一个用于第一个空格之后的项目:

import re

lines = ['&{dict1_name}=   key1=key1value   key2=key2value',
         '&{dict2_name}=   key1=key1value']

name = re.compile('^&\{(\w+)\}=')
item = re.compile('(\w+)=(\w+)')

for line in lines:
    n = name.search(line).group(1)
    i = '{{{}}}'.format(','.join("'{}' : '{}'".format(m.group(1), m.group(2)) for m in item.finditer(' '.join(line.split()[1:]))))
    exec('{} = {}'.format(n, i))
    print(locals()[n])

输出

{'key2': 'key2value', 'key1': 'key1value'}
{'key1': 'key1value'}

说明

'^&\{(\w+)\}=''&'匹配,后跟由花括号(\w+)包围的单词'\{', '\}'。第二个正则表达式匹配由'='连接的任何单词。该行:

i = '{{{}}}'.format(','.join("'{}' : '{}'".format(m.group(1), m.group(2)) for m in item.finditer(' '.join(line.split()[1:]))))

创建字典文字,最后使用exec创建具有所需名称的字典。您可以访问查询本地的字典的值。

答案 1 :(得分:1)

结合dict理解使用两个表达式:

import re

junkystring = """
lorem ipsum
&{dict1_name}=   key1=key1value   key2=key2value
&{dict2_name}=   key1=key1value
lorem ipsum
"""

rx_outer = re.compile(r'^&{(?P<dict_name>[^{}]+)}(?P<values>.+)', re.M)
rx_inner = re.compile(r'(?P<key>\w+)=(?P<value>\w+)')

result = {m_outer.group('dict_name'): {m_inner.group('key'): m_inner.group('value')
            for m_inner in rx_inner.finditer(m_outer.group('values'))}
            for m_outer in rx_outer.finditer(junkystring)}

print(result)

哪个生产

{'dict1_name': {'key1': 'key1value', 'key2': 'key2value'}, 
 'dict2_name': {'key1': 'key1value'}}


两个表达式为

^&{(?P<dict_name>[^{}]+)}(?P<values>.+)
# the outer format

请参见a demo on regex101.com。还有第二个

(?P<key>\w+)=(?P<value>\w+)
# the key/value pairs

也请参见a demo for the latter on regex101.com

其余的只是简单地对dict理解中的不同表达式进行排序。

答案 2 :(得分:1)

如您所指出的,您将需要解决捕获组仅捕获最后一个匹配这一事实。一种方法是利用文件中的行是可迭代的这一事实,并使用两种模式:一种用于“行名”,一种用于其多个键值对:*

env.readTextFile(params.get("input"))
   .flatMap(someCsvRowParseFunction())

*诚然,由于您每行要进行两次搜索,因此效率低下。但是对于中等大小的文件,应该没问题。

结果:

import re

dname = re.compile(r'^&{(?P<name>\w+)}=')
keyval = re.compile(r'(?P<key>\w+)=(?P<val>\w+)')

data = {}
with open('input/keyvals.txt') as f:
    for line in f:
        name = dname.search(line)
        if name:
            name = name.group('name')
            data[name] = dict(keyval.findall(line))

请注意,>>> from pprint import pprint >>> pprint(data) {'d5': {'key1': '28f_s', 'key2': 'key2value'}, 'name1': {'key1': '5', 'key2': 'x'}, 'othername2': {'key1': 'key1value', 'key2': '7'}} 与Unicode文字字符匹配。


示例输入keyvals.txt:

\w

答案 3 :(得分:0)

Brad's answer为基础,我进行了一些修改。正如我在对他的答复的评论中提到的那样,它在空白行或注释行中失败。我对其进行了修改,以忽略这些内容并继续。我还添加了对空格的处理:现在它匹配字典名称中的空格,但是用下划线替换它们,因为python变量名中不能包含空格。按键是字符串,因此保持不变。

import re


    def robot_to_python(filename):
        """
        This function can be used to convert robot variable files containing dicts to a python
        variables file containing python dict that can be imported by both python and robot.
        """
        dname = re.compile(r"^&{(?P<name>.+)}=")
        keyval = re.compile(r"(?P<key>[\w|:]+)=(?P<val>[\w|:]+)")

        data = {}
        with open(filename + '.robot') as f:
            for line in f:
                n = dname.search(line)
                if n:
                    name = dname.search(line).group("name").replace(" ", "_")

                    if name:
                        data[name] = dict(keyval.findall(line))

        with open(filename + '.py', 'w') as file:
            for dictionary in data.items():
                dict_name = dictionary[0]
                file.write(dict_name + " = { \n")
                keyvals = dictionary[1]
                for k in sorted(keyvals.keys()):
                    file.write("'%s':'%s', \n" % (k, keyvals[k]))
                file.write("}\n\n")
        file.close()