【问题标题】:Regex to parse delimited string with key/value pairs (python)正则表达式用键/值对解析分隔字符串(python)
【发布时间】:2019-05-25 16:17:53
【问题描述】:

我有文本格式的数据,其中键/值对用分号分隔,后面可能跟空格,也可能不是,例如“;”或“;”,甚至“;”。对之间总会有分号,字符串以分号结尾。

键和值用空格分隔。

这个字符串是扁平的。从来没有任何嵌套的东西。字符串总是被引用,而数值从不被引用。我可以指望这在输入中是一致的。比如,

'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'

最终结果是

{'cheese': "stilton", 'pigeons': 17, 'color': "blue"; 'why': "because I said so"}

不同的字符串可能包含不同的键/值对,我无法提前知道会出现哪些键。所以这是同样有效的输入字符串:

mass 6.02 ; mammal "gerbil";telephone "+1 903 555-1212"; size "A1";

我认为将字符串拆分为列表的正则表达式将是一个好的开始,然后只需两次遍历列表即可构建字典。类似的东西

x = PATTERN.split(s)
d = {}
for i in range(0, len(x), 2):
    d[x[i]] = d[x[i+1]]

这需要像 ['cheese', 'stilton', 'pigeons', 17, 'color', 'blue', 'why', 'because I said so'] 这样的列表。但我想不出一个正则表达式来获得这种形式。我最近的是

([^;[\s]*]+)

返回

['', 'cheese', ' ', '"stilton"', ';', 'pigeons', ' ', '17', '; ', 'color', ' ', '"blue"', '; ', 'why', ' ', '"because', ' ', 'I', ' ', 'said', ' ', 'so"', ';']

当然,很容易迭代三个并选择键/值对并忽略捕获的分隔符,但我想知道是否有不同的正则表达式不会捕获分隔符。有什么建议吗?

【问题讨论】:

    标签: python regex regex-group


    【解决方案1】:

    这里使用findall() 可能比split() 更容易。这将允许您使用捕获组来提取您想要的部分。然后你可以拆分组、清理等:

    import re
    s = 'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'
    pairs = re.findall(r'(\S+?) (.+?);', s)
    
    d = {}
    for k, v in pairs:
        if  v.isdigit():
            v = int(v)
        else:
            v = v.strip('"')
        d[k] = v
    print(d)
    

    结果

    {'cheese': 'stilton',
     'pigeons': 17,
     'color': 'blue',
     'why': 'because I said so'}
    

    当然,这假设您没有在数据中的任何地方使用;

    【讨论】:

      【解决方案2】:

      你可以使用

      r'(\w+)\s+("[^"]*"|[^\s;]+)'
      

      使用re.findall 匹配和提取您的数据,如果第一个替代项匹配,则对第2 组值进行后处理以删除一个尾随和一个前导" 字符,然后创建一个字典条目。

      请参阅regex demo

      详情

      • (\w+) - 第 1 组(键):一个或多个单词字符
      • \s+ - 1+ 空白字符
      • ("[^"]*"|[^\s;]+) - 第 2 组:",除 " 之外的 0+ 个字符,然后是 " 或除空格和 ; 之外的 1 个或多个字符

      Python demo:

      import re
      rx = r'(\w+)\s+("[^"]*"|[^\s;]+)'
      s = 'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'
      result = {}
      for key,val in re.findall(rx, s):
          if val.startswith('"') and val.endswith('"'):
              val = val[1:-1]
          result[key]=val
      
      print(result)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-04
        • 2016-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-17
        • 1970-01-01
        相关资源
        最近更新 更多