python字典可以使用re.compile作为密钥吗?

时间:2017-01-23 11:39:19

标签: python regex dictionary hashtable

我们有10-20个字典遵循这种基本格式,关键是要分配的值,值是正则表达式:

osTypeRE = collections.OrderedDict([
    ('WINDOWS', re.compile('^.*(windows|WIN2008|WIN2003).*$', re.MULTILINE+re.IGNORECASE)),
    ('LINUX/UNIX', re.compile('^.*(unix|linux|ubuntu|red hat|redhat|RHEL|CentOS|CENT OS|Debian|SLES|SUSE|freebsd|free bsd|AIX|Solaris|SunOS).*$', re.MULTILINE+re.IGNORECASE)),
    ('MAC', re.compile('^.*(mac os x).*$', re.MULTILINE+re.IGNORECASE)),
    ('STRATUS VOS', re.compile('^.*(VOS|Stratus).*$', re.MULTILINE+re.IGNORECASE)),
    ('MAINFRAME', re.compile('^.*(OS400|AS400).*$', re.MULTILINE+re.IGNORECASE)),
    ('CISCO IOS', re.compile('^.*(IOS).*$', re.MULTILINE+re.IGNORECASE)),
    ('NETWARE/OES', re.compile('^.*(NETWARE|OES|Open Enterprise Server).*$', re.MULTILINE+re.IGNORECASE)),
    ('OPENVMS', re.compile('^.*(VMS).*$', re.MULTILINE+re.IGNORECASE)),
    ('HYPERVISOR', re.compile('^.*(ESX).*$', re.MULTILINE+re.IGNORECASE)),
    ('HP NONSTOP', re.compile('^.*(NONSTOP|Tandem|NON STOP).*|.*(H06.20).*$', re.MULTILINE+re.IGNORECASE)),
    ('EMBEDDED', re.compile('^.*(QNX).*$', re.MULTILINE+re.IGNORECASE))
])

这些类型的词典已被证明非常有用,因为它允许我们标准化来自多个管理系统的计算机信息,以便可以协调信息。

唯一的问题是它太慢了。这是我们使用这种类型的字典来规范化数据的函数:

def reg_lookup(lookup, re_dict):
    value = "INDETERMINATE"
    for key, reg_ex in  re_dict.items():
        matched = reg_ex.search(lookup)
        if matched:
            value = key.upper()
            break
    return value

所以基本上,我们循环通过字典值(正则表达式),当我们找到匹配时,我们采用密钥,这将成为新的标准化值。

但是由于我们通过字典循环,我们正在失去与字典类型哈希表相关的速度。但是我们如何克服这个呢?我可以简单地交换这些词典中的键值和值对吗?但那么我的reg_lookup函数将如何更改并且会更快?

另一个例子字典:

osVerRE = collections.OrderedDict([
    ('WINDOWS', collections.OrderedDict([
        ('WINDOWS SERVER 2000 SERIES', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2000).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2003 ENTERPRISE', re.compile('^(?=.*WINDOWS)(?=.*SERVER|.* SR )(?=.*2003)(?=.*ENTERPRISE|.* Ent).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2003 STANDARD', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2003)(?=.*STANDARD|.*STD).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2003 SERIES', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2003).*|(?=.*WIN2003).*|(?=.*Windows)(?=.*SERVER)(?=.*2k3).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2008 ENTERPRISE', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2008)(?=.*ENTERPRISE|.* ENT).*|(?=.*WINDOWS)(?=.*SERVER)(?=.*2K8)(?=.*ENTERPRISE|.* ENT).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2008 STANDARD', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2008)(?=.*STANDARD|.*STD).*|(?=.*WINDOWS)(?=.*SERVER)(?=.*2K8)(?=.*STANDARD|.*STD).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2008 DATACENTER', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2008)(?=.*DATACENTER).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2008 SERIES', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2008).*|(?=.*WINDOWS)(?=.*SERVER)(?=.*2K8).*|(?=.*WIN2008).*|(?=.*WINDOWS 2K8 R2).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2012 DATACENTER', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2012)(?=.*DATACENTER).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2012 STANDARD', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2012)(?=.*STANDARD).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER 2012 SERIES', re.compile('^(?=.*WINDOWS)(?=.*SERVER)(?=.*2012).*|(?=.*WINDOWS)(?=.*2012 R2).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS NT 4.0', re.compile('^(?=.*WINDOWS)(?=.*NT)(?=.*4\.0).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS XP PROFESSIONAL', re.compile('^(?=.*WINDOWS)(?=.*XP)(?=.*PROFESSIONAL).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 10 PROFESSIONAL', re.compile('^(?=.*WINDOWS)(?=.*10)(?=.*PRO).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 7 ENTERPRISE', re.compile('^(?=.*WINDOWS)(?=.*7)(?=.*ENTERPRISE).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 7 PROFESSIONAL', re.compile('^(?=.*WINDOWS)(?=.*7)(?=.*PROFESSIONAL).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 7 ULTIMATE', re.compile('^(?=.*WINDOWS)(?=.*7)(?=.*ULTIMATE).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS SERVER LINE', re.compile('^(?=.*WINDOWS)(?=.*SERVER).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS XP LINE', re.compile('^(?=.*WINDOWS)(?=.*XP).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 7 LINE', re.compile('^(?=.*WINDOWS)(?=.*7).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 8 LINE', re.compile('^(?=.*WINDOWS)(?=.*8).*$', re.MULTILINE+re.IGNORECASE)),
        ('WINDOWS 10 LINE', re.compile('^(?=.*WINDOWS)(?=.*10).*$', re.MULTILINE+re.IGNORECASE))
    ])),
.
.
.

3 个答案:

答案 0 :(得分:0)

为什么不进行一次正则表达式搜索(因为你的表达式是非常基本的),而不是循环遍历具有所需结果作为键的字典和每个可能的结果表达式,然后查找结果字典?

def reg_lookup(lookup, expression=re.compile('windows|WIN2008|WIN2003|unix|linux|ubuntu|red hat|redhat|RHEL|CentOS|CENT OS|Debian|SLES|SUSE|freebsd|free bsd|AIX|Solaris|SunOS|mac os x|VOS|Stratus|OS400|AS400|IOS|NETWARE|OES|Open Enterprise Server|VMS|ESX|NONSTOP|Tandem|NON STOP|H06.20|QNX', re.MULTILINE|re.IGNORECASE), dct={'windows':'WINDOWS', 'WIN2008':'WINDOWS', 'WIN2003':'WINDOWS', 'unix':'LINUX/UNIX', 'linux':'LINUX/UNIX'}):
    result = expression.search(lookup)
    if result:
        return dct[result.group()]
    else:
        return 'INDETERMINATE'

请注意H06.20匹配.的任何字符。如果您想要一个文字点,请使用H06\.20

答案 1 :(得分:0)

这是我正在使用的解决方案,至少目前是这样。它利用散列表的速度来处理先前使用字典查找匹配的项目,并在查找新项目时形成更快的字典。

我正在经历50%到75%的速度提升,具体取决于标准化的数据源。它有点令人费解,但并不是一个糟糕的解决方案......似乎提供了两全其美。想法?

fast_lookup = {"mfr":{}, "model":{}, "dev_type":{}, "os_type":{}, "os_ver":{}, "country":{}, "state":{}, }

def reg_lookup(lookup, re_dict, dict_name):
    global fast_lookup
    try:
        #First try the faster dynamically generated dictionary
        return fast_lookup[dict_name][lookup]
    except:
        #Otherwise, use the lookup dictionaries
        for key, reg_ex in  re_dict.items():
            matched = reg_ex.search(lookup)
            if matched:
                #Should a match be found, add it to the faster dictionary
                fast_lookup[dict_name][lookup] = key.upper()
                return key.upper()
        return "INDETERMINATE"

答案 2 :(得分:0)

这些是一些非常恐怖的正则表达式。看起来它们都归结为少数固定字符串,一些具有选项和所需组合,没有订单。我的第一反应是将它们包裹在 Object.keys(json).map((i) => console.log((json[i].recipeName))); 个部分中并将它们加入到一个巨大的正则表达式中,之后你可以请求该组。如果内部没有捕获组(更不用说命名的那些),你甚至可以使用lastgroup(但是你想要反转测试的顺序,并且它不会快捷)。但这会使代码变得更加丑陋。我更喜欢一种方法,其中子串不包含在(?P<name>...)中,但只是列出;那里的噪音太大了。

这是一种粗略的转换方法,用于提取字符串本身并生成一些匹配的集合:

^.*(?=.*...).*$

顺便说一句,在CPython 2.7.10中,名义问题的答案是肯定的,重新模式对象(SRE_Pattern)是可以清除的并且可以用作键,尽管这可能是依赖于实现的,因为它不是明确的在文档中指定。虽然我不确定这是否真的适用于这个问题。