使用Python正则表达式进行词元化
我正在尝试在Python中将字符串拆分成“标签”的列表。拆分时需要处理像“HappyBirthday”这样的字符串,并去掉大部分标点符号,但要保留连字符和撇号。我的起点是:
tags = re.findall("([A-Z]{2,}(?=[A-Z]|$)|[A-Z][a-z]*)|\w+-\w+|[\w']+"
我想把这个示例数据:
Jeff's dog is un-American SomeTimes! BUT NOTAlways
变成:
['Jeff's', 'dog', 'is', 'un-American', 'Some', 'Times', 'BUT', 'NOT', 'Always']
附言:抱歉我的描述不太好。我不太确定怎么解释,而且在谷歌上也没找到太多帮助。希望这个例子能清楚地说明我的意思。
编辑:我觉得我需要更准确一些,所以还有:
- 如果一个词是用连字符连接并且是大写的,比如'UN-American',那么它应该保持为一个词,输出就是'UN-American'
- 如果连字符两边有空格,比如'THIS- is'或'This - is',那么应该忽略连字符,分别输出["THIS", "is"]和["This", "is"]。
- 同样地,如果撇号在一个词的中间,比如"What'sItCalled",那么应该输出["What's", "It", "Called"]。
2 个回答
3
为了处理你编辑过的案例,我会对phynfo的精彩回答做一些修改。
>>> s = """Jeff's UN-American Un-American un-American
SomeTimes! BUT NOTAlways This- THIS-
What'sItCalled someTimes"""
>>> re.findall("[A-Z\-\']{2,}(?![a-z])|[A-Z\-\'][a-z\-\']+(?=[A-Z])|[\'\w\-]+",s)
["Jeff's", 'UN-', 'American', 'Un-', 'American', 'un-American',
'Some', 'Times', 'BUT', 'NOT', 'Always', 'This-', 'THIS-',
"What's", 'It', 'Called' 'someTimes']
你需要清楚地定义你想要的行为规则。单纯的分词并不能算是定义,你需要有类似于phynfo所提到的规则。比如,你可以设定一个规则,让'NOTAlways'
变成'NOT'
和'Always'
,同时要保留连字符。因此,'UN-American'
会被拆分,就像'UNAmerican'
也会被拆分一样。你可以尝试定义更多的规则,但当规则重叠时,你必须明确哪个规则是适用的。
24
我建议你可以这样做:
re.findall("[A-Z]{2,}(?![a-z])|[A-Z][a-z]+(?=[A-Z])|[\'\w\-]+",s)
这样处理后,你的例子会得到:
["Jeff's", 'dog', 'is', 'un-American', 'Some', 'Times', 'BUT', 'NOT', 'Always']
解释一下:这个正则表达式由三种选择组成:
[A-Z]{2,}(?![a-z])
匹配所有字母都是大写的单词。[A-Z][a-z]+(?=[A-Z])
匹配首字母大写的单词。这里的前瞻(?=[A-Z])
会在下一个大写字母之前停止匹配。[\'\w\-]+
匹配其他所有情况,也就是可能包含'
和-
的单词。