我在编写一个优雅的编码时遇到了问题。解析此要求。 (一个看起来不像是一顿C早餐)。输入是一个字符串,键值对由'分隔,'并加入了' ='。
key1=value1,key2=value2
欺骗我的部分是价值可以引用("),并在引号内,','没有结束关键。
key1=value1,key2="value2,still_value2"
这最后一部分让我使用split或re.split变得棘手,在for循环中求助于i:(。
任何人都可以表现出干净利落的方式吗?
可以假设引号仅在值中发生,并且没有空格或非字母数字字符。
答案 0 :(得分:5)
使用Split a string, respect and preserve quotes中的一些正则表达式魔术,我们可以这样做:
{{asset('path/to/your/image.jpg')}}
Per BioGeek,我的猜测,我的意思是解释正则表达式Janne Karila使用的:该模式在逗号上打破了字符串,但在此过程中尊重双引号部分(可能使用逗号)。它有两个独立的选项:不涉及引号的字符串;和双引号字符,其中双引号完成运行,除非它(反斜杠)转义:
$url = asset('path/to/your/image.jpg');
答案 1 :(得分:4)
我建议不要使用正则表达式来执行此任务,因为要解析的语言不规则。
您有一个包含多个键值对的字符串。解析这个的最好方法是不匹配它上面的模式,而是正确地标记它。
Python标准库中有一个名为shlex
的模块,它模仿POSIX shell完成的解析,并提供了一个可以根据需要轻松定制的词法分析器实现。
from shlex import shlex
def parse_kv_pairs(text, item_sep=",", value_sep="="):
"""Parse key-value pairs from a shell-like text."""
# initialize a lexer, in POSIX mode (to properly handle escaping)
lexer = shlex(text, posix=True)
# set ',' as whitespace for the lexer
# (the lexer will use this character to separate words)
lexer.whitespace = item_sep
# include '=' as a word character
# (this is done so that the lexer returns a list of key-value pairs)
# (if your option key or value contains any unquoted special character, you will need to add it here)
lexer.wordchars += value_sep
# then we separate option keys and values to build the resulting dictionary
# (maxsplit is required to make sure that '=' in value will not be a problem)
return dict(word.split(value_sep, maxsplit=1) for word in lexer)
示例运行:
parse_kv_pairs(
'key1=value1,key2=\'value2,still_value2,not_key1="not_value1"\''
)
输出
{'key1': 'value1', 'key2': 'value2,still_value2,not_key1="not_value1"'}
编辑:我忘了添加我通常坚持使用shlex而不是使用正则表达式(在这种情况下速度更快)的原因是它可以减少意外,特别是如果你需要稍后允许更多可能的输入。我从未发现如何使用正则表达式正确解析这些键值对,总会有一些输入(例如:A="B=\"1,2,3\""
)会欺骗引擎。
如果您不关心此类输入,(或者换句话说,如果您可以确保您的输入遵循常规语言的定义),正则表达式就完全可以了。
EDIT2: split
有maxsplit
参数,使用比分割/切片/连接更清晰。感谢@cdlane的声音输入!
答案 2 :(得分:3)
我提出了这个正则表达式解决方案:
import re
match = re.findall(r'([^=]+)=(("[^"]+")|([^,]+)),?', 'key1=value1,key2=value2,key3="value3,stillvalue3",key4=value4')
这使得"匹配":
[('key1', 'value1', '', 'value1'), ('key2', 'value2', '', 'value2'), ('key3', '"value3,stillvalue3"', '"value3,stillvalue3"', ''), ('key4', 'value4', '', 'value4')]
然后你可以创建一个for循环来获取键和值:
for m in match:
key = m[0]
value = m[1]
答案 3 :(得分:2)
我不确定它看起来不像C早餐而且非常优雅:)
data = {}
original = 'key1=value1,key2="value2,still_value2"'
converted = ''
is_open = False
for c in original:
if c == ',' and not is_open:
c = '\n'
elif c in ('"',"'"):
is_open = not is_open
converted += c
for item in converted.split('\n'):
k, v = item.split('=')
data[k] = v
答案 4 :(得分:1)
根据其他几个答案,我提出了以下解决方案:
import re
import itertools
data = 'key1=value1,key2="value2,still_value2"'
# Based on Alan Moore's answer on http://stackoverflow.com/questions/2785755/how-to-split-but-ignore-separators-in-quoted-strings-in-python
def split_on_non_quoted_equals(string):
return re.split('''=(?=(?:[^'"]|'[^']*'|"[^"]*")*$)''', string)
def split_on_non_quoted_comma(string):
return re.split(''',(?=(?:[^'"]|'[^']*'|"[^"]*")*$)''', string)
split1 = split_on_non_quoted_equals(data)
split2 = map(lambda x: split_on_non_quoted_comma(x), split1)
# 'Unpack' the sublists in to a single list. Based on Alex Martelli's answer on http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python
flattened = [item for sublist in split2 for item in sublist]
# Convert alternating elements of a list into keys and values of a dictionary. Based on Sven Marnach's answer on http://stackoverflow.com/questions/6900955/python-convert-list-to-dictionary
d = dict(itertools.izip_longest(*[iter(flattened)] * 2, fillvalue=""))
生成的d
是以下字典:
{'key1': 'value1', 'key2': '"value2,still_value2"'}