如何使用带引号的逗号分隔逗号分隔的键值对

Add*_*son 6 python parsing

我知道有许多关于解析逗号分隔值的其他帖子,但我找不到分割键值对并处理引用逗号的帖子.

我有这样的字符串:

age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"
Run Code Online (Sandbox Code Playgroud)

我希望得到这个:

{
  'age': '12',
  'name': 'bob',
  'hobbies': 'games,reading',
  'phrase': "I'm cool!",
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用shlex这样的:

lexer = shlex.shlex('''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"''')
lexer.whitespace_split = True
lexer.whitespace = ','
props = dict(pair.split('=', 1) for pair in lexer)
Run Code Online (Sandbox Code Playgroud)

麻烦的是shlexhobbies条目分成两个标记,即hobbies="gamesreading".有没有办法让双引号考虑在内?或者我可以使用另一个模块吗?

编辑:修正了拼写错误 whitespace_split

编辑2:我不喜欢使用shlex.正则表达式也很好,但我不知道如何处理匹配的引号.

pis*_*che 7

您只需要shlex在POSIX模式下使用词法分析器.

posix=True创建词法分析器时添加.

(参见shlex解析规则)

lexer = shlex.shlex('''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"''', posix=True)
lexer.whitespace_split = True
lexer.whitespace = ','
props = dict(pair.split('=', 1) for pair in lexer)
Run Code Online (Sandbox Code Playgroud)

产出:

{'age': '12', 'phrase': "I'm cool!", 'hobbies': 'games,reading', 'name': 'bob'}
Run Code Online (Sandbox Code Playgroud)

PS:只要输入可以包含带引号=,字符,正则表达式就无法解析键值对.即使预处理字符串也无法使输入被正则表达式解析,因为这种输入不能正式定义为常规语言.


Håk*_*Lid 5

可以使用正则表达式。在这种情况下,它实际上也可能是最佳选择。我认为这适用于大多数输入,甚至像这样的转义引号:phrase='I\'m cool'

使用 VERBOSE 标志,可以使复杂的正则表达式非常具有可读性。

import re
text = '''age=12,name=bob,hobbies="games,reading",phrase="I'm cool!"'''
regex = re.compile(
    r'''
        (?P<key>\w+)=      # Key consists of only alphanumerics
        (?P<quote>["']?)   # Optional quote character.
        (?P<value>.*?)     # Value is a non greedy match
        (?P=quote)         # Closing quote equals the first.
        ($|,)              # Entry ends with comma or end of string
    ''',
    re.VERBOSE
    )

d = {match.group('key'): match.group('value') for match in regex.finditer(text)}

print(d)  # {'name': 'bob', 'phrase': "I'm cool!", 'age': '12', 'hobbies': 'games,reading'}
Run Code Online (Sandbox Code Playgroud)