字典键上的正则表达式匹配
Posted
技术标签:
【中文标题】字典键上的正则表达式匹配【英文标题】:Regex matching on dictionary keys 【发布时间】:2016-06-01 02:12:50 【问题描述】:假设我们有一本字典:'Hello World': value1, 'Testing': value2
现在我们需要在字典中查找一个单词。密钥 K 需要与“Hello World”或“Testing”完全匹配才能使用。
所以让我们的text = 'hello world'
我们仍然希望它返回value1
那么我们如何处理文本到键的正则表达式匹配呢?理想情况下,我们不想遍历字典
编辑:间距方面只是一个简单的例子。文本可能会改变大小写,是我们想要匹配的数字和字母的组合。我们通常会使用正则表达式模式
【问题讨论】:
使用" ".join(text.split()).title()
?
谢谢,但是更复杂的正则表达式模式呢?这可能不仅仅是间距问题
请在您的问题中至少添加一个预期的输入/输出...我不确定您到底需要什么...!
有点完全违背了使用字典的目的,你的数据来自哪里?
你的问题很不清楚。您应该提供更多输入和所需输出的示例,否则 zondo 的评论会回答您的问题。
【参考方案1】:
也许考虑规范化你的字典中的键。使用不带分隔符的 python 的 string.split 函数将删除所有空格。
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'
【讨论】:
如果你有"cat dog"
和"catd og"
这两个字怎么办?
这些都将被规范化为“catdog”
这是我的观点,您的解决方案不起作用。如果您的原始字典是d = "Cat Dog": "value1", "Catd Og": "value2"
,那么您只会丢失其中一个。
啊,我明白了,最好在连接中使用空格:d = " ".join(k.split()).lower(): v for k, v in d.items () 这将留下: d = 'cat dog': 'value1', 'catd og': 'value2'【参考方案2】:
你正在做的几乎是在击败dict
s 的效率,所以你最好制作自己的dict
-like 类。这是一个简单的例子:
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
>>>
从那里,您可以添加更多 dict
功能。请参阅Data Model docs。
它确实打破了你的“无迭代”条款,但如果你想推广到正则表达式,我不确定有什么办法。
【讨论】:
也许是因为 OP 说他不想遍历键,而您的解决方案正是这样做的?但我同意在他的案例中似乎没有办法绕过某种迭代。 @gill 很公平,我读了 3 次都错过了。不过,他确实说“理想”,我不确定是否有办法解决。 他确实做到了。但看起来如果 OP 没有这个(我认为)无法达到的理想,那么我们就不会有这个问题。附言。我没有对你投反对票:) @gill 哦,我知道。如果不立即发表评论,投反对票的人不会留下来解释自己。 ^^ 感谢所有意见,但请不要假设我是男性。【参考方案3】:为了帮助查找,您可以排序和平分查找从哪里开始查找以缩小查找范围,当您找到匹配项或当前键是 > 您正在查找的内容时。
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()]
您可以使用正则表达式来查找匹配项,也可以通过分割、剥离等方式对数据进行规范化。这完全取决于输入的外观,但通过分组,您至少可以减少必须进行的比较量.
【讨论】:
【参考方案4】:我愿意,
>>> 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'
【讨论】:
以上是关于字典键上的正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章