正则表达式可以用作字典中的键吗?

时间:2015-10-26 10:40:14

标签: python regex dictionary

我想创建一个字典,其中键是正则表达式:

d = {'a.*': some_value1, 'b.*': some_value2}

然后,当我查看字典时:

d['apple']

我希望将apple 'apple'与正则表达式的键匹配。如果与key / regular-expression完全匹配,则应返回相应的值。

例如,'apple'完全匹配正则表达式'a.*',因此,应返回some_value1

当然,所有这些都假定正则表达式键不冲突(即两个键不应该完全匹配相同的字符串)。假设在构建密钥时我可以手动处理这个要求。

这在Python中可行吗?如果是这样,它将是一个非常优雅和强大的结构!

5 个答案:

答案 0 :(得分:10)

Python字典实现为hash tables - 这意味着通过内部散列mydict[myvalue],任何myvalue查找都非常快。使用正则表达式作为键将取消此功能。您应该使用简单的列表或元组,而不是使用字典,其中每个项目都是格式为(pattern/compiled regular expression, value)的元组,并扫描它们直到正则表达式通过。这也使您能够使用正则表达式的顺序(例如,从特定表达式到通用表达式):

import re

LOOKUPS  = [
    ('a.*', 'a'),
    ('b.*', 'b'),
]

def lookup(s, lookups):
    for pattern, value in lookups:
        if re.search(pattern, s):
            return value
    return None

print(lookup("apple", LOOKUPS))

另请参阅Django的url resolver以了解(非常)高级实现您的想法。

答案 1 :(得分:4)

您可以使用re.compile d模式对象作为字典键:

>>> import re
>>> regex = re.compile('a.*')
>>> d = {regex: 'foo'}
>>> d[re.compile('a.*')]
'foo'

请注意,重新编译相同的正则表达式会为您提供相同的键(同一个对象,实际上是re.compile('a.*') is d.keys()[0]),因此您可以取回存储的任何内容。

然而:

  • 正如评论中所指出的,多个正则表达式可以匹配相同的字符串;
  • 字典没有排序,因此每次运行程序时,您可能会首先获得不同的匹配正则表达式;和
  • 在给定字符串可能与一个或多个O(1)键匹配的情况下,没有{regex: result, ...}方式向字典result询问regex值。

因此很难看出你为此找到了什么效用。

如果可以想出一种方法来确保没有两个键可以匹配相同的字符串,那么您可以创建一个MutableMapping子类,在您添加新键时应用此检查实现__getitem__来扫描键值对并返回参数与键正则表达式匹配的第一个值。但同样,这将是O(n)

答案 2 :(得分:1)

不确定。只需正常查看它们并检查匹配。

import re

def find_matches(d, item):
    for k in d:
        if re.match(k, item):
            return d[k]

d = {'a.*': 'a match', 'b.*': 'b match'}
for item in ['apple', 'beer']:
    print(find_matches(d, item))

结果:

a match
b match

请注意,如果在字符串的开头处找到表达式,则re.match仅生成匹配项。如果表达式可以在字符串中的任何位置,请使用re.search

答案 3 :(得分:1)

可能的解决方案:

import re


class RegexDict(dict):

    def __init__(self):
        super(RegexDict, self).__init__()

    def __getitem__(self, item):
        for k, v in self.iteritems():
            if re.match(k, item):
                return v
        raise KeyError


if __name__ == '__main__':
    d = RegexDict()

    d[r'a.*'] = 'Informed a key that starts with a'
    d[r'b.*'] = 'Informed a key that starts with b'
    d[r'\w+'] = 'Informed alphanumeric as key'
    d[r'\d+'] = 'Informed numbers as key'
    d[r'\s+'] = 'Informed spaces as key'

    print d['  ']
    print d['apple']
    print d['bee']
    print d['123']
    print d['word']
    print d['word1']

输出:

Informed spaces as key
Informed a key that starts with a
Informed a key that starts with b
Informed numbers as key
Informed alphanumeric as key
Informed alphanumeric as key

答案 4 :(得分:1)

您可以使用它。这个对我有用。您需要确保您的密钥是唯一的。

word_mapping = {
    r'\W*J\W*2\W*W\W*' : ' j2w ', r'\W*power\W*on\W*': ' poweron ', 
    r'\W*Some From Dase [0-9]*\W*' : ''
}

def correct_word_mapping(x, dic):
    for word in dic.keys():
        #if word in x:
        x = re.sub(word, dic[word], x, flags=re.IGNORECASE)
return x 

print(correct_word_mapping("power on J 2 w PowerONJ2 w", word_mapping))