我遇到了以下问题,并想知道什么是一种优雅的解决方案。 假设我们有两个字符串:
string1 = "I love to eat $(fruit)"
string2 = "I love to eat apples"
这些字符串之间的唯一区别是$(fruit)
和apples
。
因此,我发现水果是苹果,并且可以返回dict{fruit:apples}
。
另一个例子是:
string1 = "I have $(food1), $(food2), $(food3) for lunch"
string2 = "I have rice, soup, vegetables for lunch"
我希望得到一个dict{food1:rice, food2:soup, food3:vegetables}
。
任何人都知道如何实现它?
修改:
我认为我需要功能更强大。
ex.
string1 = "I want to go to $(place)"
string2 = "I want to go to North America"
result: {place : North America}
ex.
string1 = "I won $(index)place in the competition"
string2 = "I won firstplace in the competition"
result: {index : first}
规则将是:映射字符串的不同部分并将它们作为字典
所以我想使用str.split()或尝试拆分字符串的所有答案都将不起作用。没有规则说明将什么字符用作字符串中的分隔符。
答案 0 :(得分:5)
我认为这可以通过基于正则表达式的拆分完全完成。这也应该处理标点符号和其他特殊字符(空格分隔不足)。
Uncaught TypeError: a.insertBefore is not a function
对于您的示例,此返回
import re
p = re.compile(r'[^\w$()]+')
mapping = {
x[2:-1]: y for x, y in zip(p.split(string1), p.split(string2)) if x != y}
和
{'fruit': 'apple'}
答案 1 :(得分:1)
我想这可以解决问题。
s_1 = 'I had $(food_1), $(food_2) and $(food_3) for lunch'
s_2 = 'I had rice, meat and vegetable for lunch'
result = {}
for elem1, elem2 in zip(s_1.split(), s_2.split()):
if elem1.startswith('$'):
result[elem1.strip(',')[2:-1]] = elem2
print result
# {'food_3': 'vegetable', 'food_2': 'meat', 'food_1': 'rice,'}
答案 2 :(得分:1)
一种解决方案是将$(name)
替换为(?P<name>.*)
并将其用作正则表达式:
def make_regex(text):
replaced = re.sub(r'\$\((\w+)\)', r'(?P<\1>.*)', text)
return re.compile(replaced)
def find_mappings(mapper, text):
return make_regex(mapper).match(text).groupdict()
样品用量:
>>> string1 = "I have $(food1), $(food2), $(food3) for lunch"
>>> string2 = "I have rice, soup, vegetable for lunch"
>>> string3 = "I have rice rice rice, soup, vegetable for lunch"
>>> make_regex(string1).pattern
'I have (?P<food1>.*), (?P<food2>.*), (?P<food3>.*) for lunch'
>>> find_mappings(string1, string2)
{'food1': 'rice', 'food3': 'vegetable', 'food2': 'soup'}
>>> find_mappings(string1, string3)
{'food1': 'rice rice rice', 'food3': 'vegetable', 'food2': 'soup'}
请注意,这可以处理非字母数字标记(请参见food1
和rice rice rice
)。显然,这可能会进行大量的回溯并且可能很慢。您可以调整.*
正则表达式,以尝试根据对“令牌”的期望使其更快。
对于准备生产的代码,您需要re.escape
组之外的(?P<name>.*)
部分。要做些麻烦,因为您必须“分割”该字符串并在每个片段上调用re.escape
,将它们放在一起并调用re.compile
。
自从我的答案被接受以来,我想包含一个更强大的正则表达式版本:
def make_regex(text):
regex = ''.join(map(extract_and_escape, re.split(r'\$\(', text)))
return re.compile(regex)
def extract_and_escape(partial_text):
m = re.match(r'(\w+)\)', partial_text)
if m:
group_name = m.group(1)
return ('(?P<%s>.*)' % group_name) + re.escape(partial_text[len(group_name)+1:])
return re.escape(partial_text)
这避免了当文本包含特殊的正则表达式字符(例如I have $(food1) and it costs $$$
时出现的问题。第一个解决方案最终会考虑将$$$
设为$
锚点的三倍(这会失败),可靠的解决方案使它们逃脱了。
答案 3 :(得分:0)
您可以这样做:
>>> dict((x.strip('$(),'),y.strip(',')) for x,y in zip(string1.split(), string2.split()) if x!=y)
{'food1': 'rice', 'food2': 'soup', 'food3': 'vegetable'}
或使用正则表达式:
>>> import re
>>> dict((x, y) for x,y in zip(re.findall(r'\w+', string1), re.findall(r'\w+', string2)) if x!=y)
{'food1': 'rice', 'food2': 'soup', 'food3': 'vegetable'}
答案 4 :(得分:0)
如果您不想使用正则表达式:
string1 = "I have $(food1), $(food2), $(food3) for lunch"
string2 = "I have rice, soup, vegetable for lunch"
trans_table = str.maketrans({'$': '', '(': '', ')': '', ',': ''})
{
substr1.translate(trans_table): substr2.translate(trans_table)
for substr1, substr2 in zip(string1.split(),string2.split())
if substr1 != substr2
}
输出:
{'food1': 'rice', 'food2': 'soup', 'food3': 'vegetable'}
或者,更灵活一些:
def substr_parser(substr, chars_to_ignore='$(),'):
trans_table = str.maketrans({char: '' for char in chars_to_ignore})
substr = substr.translate(trans_table)
# More handling here
return substr
{
substr_parser(substr1): substr_parser(substr2)
for substr1, substr2 in zip(string1.split(),string2.split())
if substr1 != substr2
}
与上述输出相同。
答案 5 :(得分:0)
您可以使用re
:
import re
def get_dict(a, b):
keys, values = re.findall('(?<=\$\().*?(?=\))', a), re.findall(re.sub('\$\(.*?\)', '(\w+)', a), b)
return dict(zip(keys, values if not isinstance(_values[0], tuple) else _values[0]))
d = [["I love to eat $(fruit)", "I love to eat apple"], ["I have $(food1), $(food2), $(food3) for lunch", "I have rice, soup, vegetable for lunch"]]
results = [get_dict(*i) for i in d]
输出:
[{'fruit': 'apple'}, {'food3': 'vegetable', 'food2': 'soup', 'food1': 'rice'}]
答案 6 :(得分:0)
zip
与dictionary comprehension
结合使用效果很好,在这里我们可以zip
这两个列表,并且只接受不相等的对。
l = [*zip(s1.split(),s2.split())]
d = {i[0].strip('$(),'): i[1] for i in l if i[0] != i[1] }