Python 字典键上的正则表达式匹配
假设我们有一个字典:Python 字典键上的正则表达式匹配,python,regex,dictionary,key,normalization,Python,Regex,Dictionary,Key,Normalization,假设我们有一个字典:{'Hello World':value1,'Testing':value2} 现在我们需要在字典里查一个词。密钥K需要与“Hello World”或“Testing”完全匹配才能使用 因此,让我们的text='hello world'我们仍然希望它返回value1 那么我们如何处理文本与键的正则表达式匹配呢?理想情况下,我们不想反复浏览字典 编辑:间距方面只是一个简单的例子。文本可能会因大小写的不同而变化,可能是我们希望匹配的数字和字母的组合。我们通常会使用正则表达式模式
{'Hello World':value1,'Testing':value2}
现在我们需要在字典里查一个词。密钥K需要与“Hello World”或“Testing”完全匹配才能使用
因此,让我们的text='hello world'
我们仍然希望它返回value1
那么我们如何处理文本与键的正则表达式匹配呢?理想情况下,我们不想反复浏览字典
编辑:间距方面只是一个简单的例子。文本可能会因大小写的不同而变化,可能是我们希望匹配的数字和字母的组合。我们通常会使用正则表达式模式
>>> d = {'Hello World': 'value1', 'Testing': 'value2'}
>>> text = 'hello world'
>>> key = next(x for x in (re.search(r'(?i)' + re.sub(r'(\s)+', r'\1', text.strip()), i) for i in d.keys()) if x).group()
>>> d[key]
'value1'
为了帮助查找,您可以进行排序和对分,以找到开始查找的位置,缩小查找范围,并在找到匹配项时中断查找,或者当前键为>您正在查找的内容
from bisect import bisect_left
d = {'Hello World': "value1", 'Testing': "value2"}
items = sorted([(k.lstrip().lower(),v) for k, v in d.items()])
text = 'hello world'
ind = bisect_left(items,(text.lower(),), hi=len(items) - 1)
# use items[ind]
或者使用每个键的前几个字母创建映射:
from collections import defaultdict
lookup_mapping = defaultdict(list)
for k in d:
lookup_mapping[k[:2].lower().lstrip()].append(k)
poss = lookup_mapping[text[:2].lower().lstrip()]
您可以使用正则表达式查找匹配项,也可以通过切分、剥离等方式对数据进行规范化。。它完全取决于输入可以是什么样子,但是通过分组,你至少可以减少你必须做的比较量。
也许考虑在你的DIST中规范键。使用Python的函数,没有定界符将删除所有空白。
def normalize(word):
return " ".join(word.split()).lower()
d = {'Hello World': 'value1', 'Testing': 'value2'}
d = {normalize(k): v for k, v in d.items()}
print(d)
>>> {'hello world': 'value1', 'testing': 'value2'}
text = 'hello world'
d[normalize(text)]
>>> 'value1'
你所做的几乎是破坏了
dict
s的效率,因此你最好自己制作一个类似dict
的类。下面是一个简单的例子:
from re import search, I
class RegexMap(object):
def __init__(self, *args, **kwargs):
self._items = dict(*args, **kwargs)
def __getitem__(self, key):
for regex in self._items.keys():
if search(regex, key, I):
return self._items[regex]
raise KeyError
用法:
>>> rm = RegexMap({'\s*hello\s*world\s*':1, '\s*foo\s*bar\s*':2})
>>> rm['Hello World']
1
>>> rm['foobar']
2
>>> rm['baz']
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
rm['baz']
File "C:\Users\dmurphy\Documents\python\_t.py", line 10, in __getitem__
raise KeyError
KeyError
>>>
>>rm=RegexMap({'\s*hello\s*world\s*':1'\s*foo\s*bar\s*':2})
>>>rm['Hello World']
1.
>>>rm['foobar']
2.
>>>rm['baz']
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
rm['baz']
文件“C:\Users\dmurphy\Documents\python\\u t.py”,第10行,在\uu getitem中__
上升键错误
关键错误
>>>
从那里,您可以添加更多的dict
功能。看
它确实打破了您的“no iteration”子句,但是如果您想将其推广到正则表达式,我不确定是否有任何方法可以绕过它。使用
“”。join(text.split()).title()
?谢谢,但是更复杂的正则表达式模式呢?这可能不仅仅是一个间隔问题请在您的问题中至少添加一个预期的输入/输出。。。我不确定你到底需要什么。。!有点完全违背了使用dict的目的,你的数据来自哪里?你的问题很不清楚。你应该给出更多输入和所需输出的示例,否则zondo的评论会回答你的问题。如果你有“catdog”
和“catd og”
?这两个词都会被规范化为“catdog”,这是我的观点,你的解决方案不起作用。如果你原来的字典是d={“Cat Dog”:“value1”,“Catd Og”:“value2”}
,你只会丢失其中一个。啊,我明白了-那么最好在join中使用一个空格:d={“。join(k.split()).lower():v代表k,v代表d.items()}这将留下:d={“Cat Dog”:“value1”,“Catd Og”:“value2”}也许是因为OP说他不想迭代键,而你的解决方案就是这么做的?但我同意,在他的案例中,似乎没有办法避免某种重复。@gill说得很公平,我读了三遍都没有读到。不过他确实说了“理想”,我不确定有什么办法可以解决这个问题。他确实说了。但看起来,如果OP没有这个(我认为)无法实现的理想,那么我们就不会有这个问题。另外,我没有投你反对票:)@gill哦,我知道。如果不立即发表评论,下层选民不会留下来解释自己。^^我感谢所有的意见,但请不要假设我是男性。