?? 本文主要介绍 Python 的 REfO 的基本使用方法。
1.1 简介
??REfO,Regular Expressions for Objects。它和 Python 的 re 模块提供相似的功能。但是 REfO 是为对象(object)序列设计的,re 模块是为字符串(string)设计的。
1.2 使用方法
??REfO 的语法与 Python 的 re 有点不同,与 pyparsing 的语法相似。
1.2.1 符号表示
1.2.1.1 普通字符
??普通字符,使用 Literal() ,例如:
正则表达式 | 语法 |
---|
“a” | Literal(“a”) | “ab” | Literal(“a”) + Literal(“b”) | “1” | Literal(“1”) |
1.2.1.2 特殊符号
??下面为几个特殊符号的语法表示:
符号 | 语法 |
---|
? | Question() | * | Star() | + | Plus() | 任意字符 | Any() |
??具体如下:
正则表达式 | 语法 |
---|
“a?” | Question(a) | “a*” | Star(Literal(“a”)) | “(ab)+” | Plus(Literal(a) + Literal(b)) | “(bb)*?” | Star(Literal(b) + Literal(b), greedy=False) |
??上面的第 4 个样例中,有一个为 greedy 的参数,当为 False 时,表示非贪婪匹配;当为 True 时,表示贪婪匹配。其中,Star() 、Plus() 和 Question() 都有这个参数。
1.2.2 匹配操作
1.2.2.1 match()
??函数 match() 只返回第一个匹配。样例如下:
import refo
sentence = "ababab"
a = refo.Literal("a")
b = refo.Literal("b")
pattern = a + b
result = refo.match(pattern, sentence)
start, end = result.span()
print('start={}, end={}'.format(start, end))
print(sentence[start:end])
输出:
start=0, end=2
ab
1.2.2.2 finditer()
??函数 finditer() 返回所有匹配的一个迭代器。样例如下:
import refo
sentence = "ababab"
a = refo.Literal("a")
b = refo.Literal("b")
pattern = a + b
for m in refo.finditer(pattern, sentence):
start, end = m.span()
print('start={}, end={}'.format(start, end))
print(sentence[start:end])
输出:
start=0, end=2
ab
start=2, end=4
ab
start=4, end=6
ab
1.2.3 匹配结果
??函数 match() 和 finditer() 的匹配结果,拥有以下函数:
函数名 | 说明 |
---|
start() | 返回匹配结果在对象列表中起始索引 | end() | 返回匹配结果在对象列表中终止索引 | span() | 返回匹配结果在对象列表中起始索引和终止索引 |
??样例如下:
import refo
sentence = "ababab"
a = refo.Literal("a")
b = refo.Literal("b")
pattern = a + b
result = refo.match(pattern, sentence)
print(result.start())
print(result.end())
print(result.span())
输出:
0
2
(0, 2)
1.3 使用样例
??前面提供样例是使用匹配的字符串(实际上字符串也属于字符序列),无法感受其与 Python 的 re 模块的区别。下面提供一个 官方样例:
from refo import finditer, Predicate, Plus
import re
import copy
class Word(object):
def __init__(self, token, pos):
self.token = token
self.pos = pos
class W(Predicate):
def __init__(self, token=".*", pos=".*"):
self.token = re.compile(token + "$")
self.pos = re.compile(pos + "$")
super(W, self).__init__(self.match)
def match(self, word):
"""
采用正则表达式同时匹配对象(word)的字符(token)和词性(pos)
"""
m1 = self.token.match(word.token)
m2 = self.pos.match(word.pos)
return m1 and m2
class Rule(object):
def __init__(self, condition=None, action=None):
assert condition and action
self.condition = condition
self.action = action
def apply(self, sentence):
for m in finditer(self.condition, sentence):
i, j = m.span()
self.action(sentence[i:j])
def capitalize_name(x):
"""
将英文单词的首字母大写
"""
for nnp in x:
orig = nnp.token
nnp.token = nnp.token.capitalize()
print('Capitalized: {} -> {}'.format(orig, nnp.token))
def feet_to_mt(x):
"""
将英尺转换为米
"""
number, units = x
orig_number_token = number.token
orig_units_token = units.token
mt = float(number.token) * 0.3048
number.token = "{0:.2}".format(mt)
units.token = "mt."
units.pos = "UNITS_METERS"
print("feet_to_mt: {} {} -> {} {}".format(
orig_number_token, orig_units_token, number.token, units.token))
rules = [
Rule(condition=W(pos="NUMBER") + W(pos="UNITS_FEET"),
action=feet_to_mt),
Rule(condition=Plus(W(token="[^A-Z].*", pos="NNP")),
action=capitalize_name),
]
sentence = "My|PRP friend|NN john|NNP smith|NNP is|VBZ 2|NUMBER " +\
"feet|UNITS_FEET taller|JJR than|IN mary|NNP Jane|NNP"
sentence = [Word(*x.split("|")) for x in sentence.split()]
original = copy.deepcopy(sentence)
for rule in rules:
rule.apply(sentence)
print("From: " + " ".join((w.token for w in original)))
print("To: " + " ".join((w.token for w in sentence)))
输出:
feet_to_mt: 2 feet -> 0.61 mt.
Capitalized: john -> John
Capitalized: smith -> Smith
Capitalized: mary -> Mary
From: My friend john smith is 2 feet taller than mary Jane
To: My friend John Smith is 0.61 mt. taller than Mary Jane
??从输出结果,我们可以看到此样例代码的目的:a. 将句子中英尺换算为米;b. 将姓名中的首字母大写。
??从上面我们可以看到,当我们需要匹配非大写字母之类的操作时,使用 Python 的 re 模块来实现会更加简便。
参考:
[1] github [2] Regular Expressions for Objects
|