在字典键上进行正则表达式匹配

5

假设我们有一个字典:{'Hello World': value1, 'Testing': value2}

现在我们需要在字典中查找一个单词。键K需要与“Hello World”或“Testing”完全匹配,才能使用。

所以让我们假设text = 'hello world',我们仍然希望它返回value1

那么我们如何处理文本与键的正则表达式匹配?理想情况下,我们不希望遍历整个字典

编辑:空格方面只是一个简单的例子。文本可能会更改大小写,是数字和字母的组合,我们希望匹配。通常我们会使用正则表达式模式


请在您的问题中至少添加一个预期的输入/输出...我不确定您需要什么准确的东西..! - Shafizadeh
这有点完全违背了使用字典的目的,你的数据从哪里来? - Padraic Cunningham
@redrubia,如果您每次都必须执行最坏情况下的O(n)扫描,则具有二次算法,对于输入列表中的每个单词,您都必须至少遍历字典中的每个键。 - Padraic Cunningham
3
你的问题不太清楚。你应该提供更多输入和期望输出的例子,否则 zondo 的评论已经回答了你的问题。 - Vincent Savard
https://www.python.org/dev/peps/pep-0455/ - GingerPlusPlus
显示剩余3条评论
4个回答

4

你所做的事情基本上是削弱了字典(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
>>> 

从那里,您可以添加更多的dict功能。请参阅数据模型文档

这确实违反了您的“无迭代”条款,但我不确定如果您想要泛化到正则表达式是否有任何解决办法。


也许是因为 OP 说他不想遍历键,而你的解决方案恰好做到了这一点?但我同意在他的情况下似乎没有绕过某种迭代的方法。 - gil
@gill 好的,我错过了,即使我读了三遍。他确实说了“理想情况”,但我不确定是否有其他办法。 - glibdud
他当然这么做了。但是看起来如果楼主没有这个(我想)无法达到的理想,我们就不会有这个问题。PS. 我没有给你点踩 :) - gil
@gill 哦,我知道。如果他们没有立即留下评论,那些给负评的人通常不会停留下来解释自己的原因。 - glibdud
我感激所有的回复,但请不要假设我是男性。 - redrubia

0

我会这样做,

>>> 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'

0
为了帮助查找,您可以对其进行排序和二分查找,以找到开始查找的位置,从而缩小查找范围,在找到匹配项或当前键大于您要查找的内容时停止查找。
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()]

你可以使用正则表达式来查找匹配项,也可以通过分割、去除空格等方式对数据进行规范化处理。具体取决于输入的格式,但通过分组,至少可以减少需要进行的比较次数。


0

或许可以考虑在字典中规范化键值。使用 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",会怎么样? - Vincent Savard
这些都将被规范化为“catdog”。 - klob
这就是我的观点,你的解决方案不起作用。如果你的原始字典是 d = {"Cat Dog": "value1", "Catd Og": "value2"},那么你只会失去其中一个。 - Vincent Savard
啊,我明白了 - 那最好在连接中使用空格:d = {" ".join(k.split()).lower(): v for k, v in d.items()}这将得到: d = {'cat dog': 'value1', 'catd og': 'value2'} - klob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接