对长字符串进行标记的另一种方法是构造一个综合正则表达式,然后使用命名组来识别标记。它需要一些设置,但识别阶段被推入 C/native 代码中,并且只需要一次通过,因此它可以非常有效。例如:
import re
tokens = {
'a': ['andy', 'alpha', 'apple'],
'b': ['baby']
}
def create_macro_re(tokens, flags=0):
"""
Given a dict in which keys are token names and values are lists
of strings that signify the token, return a macro re that encodes
the entire set of tokens.
"""
d = {}
for token, vals in tokens.items():
d[token] = '(?P<{}>{})'.format(token, '|'.join(vals))
combined = '|'.join(d.values())
return re.compile(combined, flags)
def find_tokens(macro_re, s):
"""
Given a macro re constructed by `create_macro_re()` and a string,
return a list of tuples giving the token name and actual string matched
against the token.
"""
found = []
for match in re.finditer(macro_re, s):
found.append([(t, v) for t, v in match.groupdict().items() if v is not None][0])
return found
最后一步,运行它:
macro_pat = create_macro_re(tokens, re.I)
print find_tokens(macro_pat, 'this is a string of baby apple Andy')
macro_pat 最终对应于:
re.compile(r'(?P<a>andy|alpha|apple)|(?P<b>baby)', re.IGNORECASE)
第二行打印一个元组列表,每个元组都给出了标记和与标记匹配的实际字符串:
[('b', 'baby'), ('a', 'apple'), ('a', 'Andy')]
此示例展示了如何将标记列表编译为单个正则表达式,并且可以在一次传递中有效地针对字符串运行。
未显示是它的一大优势:不仅可以通过字符串定义标记,还可以通过正则表达式定义标记。因此,如果我们想要 b 标记的替代拼写,例如,我们不必详尽地列出它们。正常的正则表达式模式就足够了。假设我们还想将“babby”识别为b 令牌。我们可以像以前一样做'b': ['baby', 'babby'],或者我们可以使用正则表达式来做同样的事情:'b': ['babb?y']。或'bab+y',如果您还想包含任意内部“b”字符。