【问题标题】:Regex to match key in YAML正则表达式匹配 YAML 中的键
【发布时间】:2018-03-09 17:46:08
【问题描述】:

我有一个看起来像这样的 yaml..!用户可以定义 N 个xyz_flovor_id,其中_flovor_id 键是通用的。目的是获取*_flavor_id 键并从中提取价值。

  server:
    tenant: "admin"
    availability_zone: "nova"
    cpu_overcommit_ratio: 1:1
    memory_overcommit_ratio: 1:1
    xyz_flovor_id: 1
    abc_flavor_id: 2

我能够计算出匹配_flovor_id 的正则表达式。然而,当试图在代码中使用它时,它会抛出错误。 这是我的代码。

def get_flavor_keys(params):
    pattern = re.compile(r'[^*]flavor_id')
    for key, value in params.iteritems():
        print value
        if key == 'server':
            if pattern.match(value):
                print 'test'

print value 正在转储整个 YAML 文件(预期)。之后立即回溯。

Traceback (most recent call last):
  File "resource_meter.py", line 150, in <module>
    get_flavor_keys(items)
  File "resource_meter.py", line 15, in get_flavor_keys
    if pattern.match(value):
TypeError: expected string or buffer

【问题讨论】:

    标签: python regex python-2.7 yaml


    【解决方案1】:

    你可以使用这个正则表达式:

    \b[^_\n]+_flavor_id:\s*(\d+)

    Click for Demo

    正则表达式解释:

    • \b - word boundary
    • [^_\n]+ - 任何不是 _ 或换行符的字符出现 1 次以上
    • _flavor_id: - 匹配 _flavor_id: 字面意思
    • \s* - 匹配 0+ 次出现的空白字符
    • (\d+) - 匹配并捕获 1 个以上的数字。这是您需要的值。

    我对 python 不太熟悉,但是 regex101 允许我们生成代码。所以,我将代码粘贴在这里,您可以使用。

    import re
    
    regex = r"\b[^_\n]+_flavor_id:\s*(\d+)"
    
    test_str = ("server:\n"
        "    tenant: \"admin\"\n"
        "    availability_zone: \"nova\"\n"
        "    cpu_overcommit_ratio: 1:1\n"
        "    memory_overcommit_ratio: 1:1\n"
        "    xyz_flavor_id: 1\n"
        "    abc_flavor_id: 2")
    
    matches = re.finditer(regex, test_str)
    
    for matchNum, match in enumerate(matches):
        matchNum = matchNum + 1
    
        print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))
    
        for groupNum in range(0, len(match.groups())):
            groupNum = groupNum + 1
    
            print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))
    

    这是我得到的输出:

    【讨论】:

      【解决方案2】:

      你需要这个正则表达式。我将它分组为键值对:

      ^\s*(?P<key>\w+_flavor_id):\s*(?P<value>\d+)
      

      Python 演示:https://repl.it/Lk5W/0

      import re
      
      regex = r"^\s*(?P<key>\w+_flavor_id):\s*(?P<value>\d+)"
      
      test_str = ("  server:\n"
          "    tenant: \"admin\"\n"
          "    availability_zone: \"nova\"\n"
          "    cpu_overcommit_ratio: 1:1\n"
          "    memory_overcommit_ratio: 1:1\n"
          "    xyz_flavor_id: 1\n"
          "    abc_flavor_id: 2\n")
      
      matches = re.finditer(regex, test_str, re.MULTILINE)
      
      for matchNum, match in enumerate(matches):
          print ("{key}:{value}".format(key = match.group('key'), value=match.group('value')))
      

      【讨论】:

        【解决方案3】:

        您会收到该错误,因为键 server 的值不是字符串,而是 dict(或 dict 的子类)。这就是您输入中的 YAML 映射(包括键 abc_flavor_id)的加载方式。

        除此之外,使用正则表达式解析 YAML(或任何其他结构化文本格式,如 HTML、XML、CVS)总是一个坏主意,因为即使不是不可能,也很难捕捉到语法的所有细微差别.如果不是,您将不需要解析器。

        例如,对文件进行细微更改,只需添加注释以供某些编辑文件的用户需要更新哪些值,就打破了简单的正则表达式方法:

        server:
          tenant: "admin"
          availability_zone: "nova"
          cpu_overcommit_ratio: 1:1
          memory_overcommit_ratio: 1:1
          xyz_flovor_id: 1
          abc_flavor_id:  # extract the value for this key
            2
        

        上面的这个 YAML 文档在语义上与您的相同,但不再适用于当前发布的其他答案。

        如果某些 YAML 加载/保存操作将您的输入转换为(同样在语义上等效):

        server: {abc_flavor_id: 2, availability_zone: nova,
          cpu_overcommit_ratio: 61, memory_overcommit_ratio: 61,
          tenant: admin, xyz_flovor_id: 1} then tweaking a dumb regular expression will not begin to suffice (this is not a construed example, this is the default way to dump your data structure in PyYAML and in ruamel.yaml using 'safe'-mode).
        

        你需要做的是,正则表达式匹配与server关联的值的键,而不是整个文档:

        import re
        import sys
        from ruamel.yaml import YAML
        
        yaml_str = """\
        server:
          tenant: "admin"
          availability_zone: "nova"
          cpu_overcommit_ratio: 1:1
          memory_overcommit_ratio: 1:1
          xyz_flovor_id: 1
          abc_flavor_id:  # extract the value for this key
            2
        """
        
        def get_flavor_keys(params):
            pattern = re.compile(r'(?P<key>.*)_flavor_id')
            ret_val = {}
            for key in params['server']:
                m = pattern.match(key)
                if m is not None:
                    ret_val[m.group('key')] = params['server'][key]
                    print('test', m.group('key'))
            return ret_val
        
        yaml = YAML(typ='safe')
        data = yaml.load(yaml_str)
        keys = get_flavor_keys(data)
        print(keys)
        

        这给了你:

        {'abc': 2}
        

        xyz_flovor_id 当然不匹配,但也许这是您帖子中的错字)。

        【讨论】:

        • 是的,同意这一点。!我重构了我的代码。!你建议的方式。!
        猜你喜欢
        • 2013-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-17
        • 1970-01-01
        • 2017-12-20
        • 1970-01-01
        相关资源
        最近更新 更多