Python正则表达式 - 拆分字母数字字符,但删除并组合带连字符的单词

时间:2015-03-21 19:40:05

标签: python regex python-3.x

我正在为一个项目解析超过两百万个文本文件,需要你的正则表达式帮助加快速度。我需要拆分单词,以便我能够使用:

text_file = re.sub(r'\W+',' ', text_file)

然而,对于带连字符的单词,我想删除连字符,但结合这个词(即非营利组织将是非营利组织而非“非”组织,“利润”)。目前,我能够通过两次搜索和替换(完全不理想)来做到这一点。最终输出将是collections.Counter()对象使用的单词列表。

def mod1(text_file):
     text_file = re.sub('\s*-\s*', '', text_file) # handling hyphens :( O(n)
     text_file = re.sub(r'\W+',' ', text_file)
     text_file = text_file.lower()
     return(text_file)

除了正则表达式之外,任何更快的处理提示都会非常感激。感谢。

3 个答案:

答案 0 :(得分:1)

使用lower()后,您可以使用re.sub(r'([a-z])-([a-z])', r'\1\2', s)删除连字符。

然后re.split(r'[^a-z]'),分开单词。

s = s.lower()
s = re.sub(r'([a-z])-([a-z])', r'\1\2', s)
s = re.split(r'[^a-z]', s)

此解决方案可能(或可能不)更快,具体取决于上使用的文本。它确实有一些可能的加速:

  • 忽略数字允许使用[a-z]代替\w
  • 首先调用
  • lower(),允许re.sub()搜索一半字母;这是[a-z]而不是[A-Za-z]
  • 假设在连字符之前和之后没有空格(因为通常应该是这种情况)允许用更快的'\s*-\s*'替换[a-z]-[a-z]

答案 1 :(得分:0)

你可以这样做,

>>> s = 'non-profit foo:?bar/buzz'
>>> ''.join(re.sub(r'\W+', ' ',i.strip()) for i in s.split('-'))
'nonprofit foo bar buzz'

OR

您可以在re.sub的替换部分中定义一项功能。

>>> s = 'non-profit foo:?bar/buzz'
>>> re.sub(r'\W+', lambda m: re.sub(r'.*', '', m.group(0)) if re.match(r'\s*-\s*$', m.group(0)) else re.sub(r'.*', r' ', m.group(0)), s)
'nonprofit foo bar buzz'

OR

保持简单......

>>> re.sub(r'\W+', lambda m: '' if re.match(r'\s*-\s*$', m.group(0)) else ' ', s)
'nonprofit foo bar buzz'

此代码将替换每个创建的匹配项。也就是说,在每次匹配之后,调用函数m。 \W+匹配一个或多个非字字符。如果找到匹配,如果matchobject.group(0)满足此\s*-\s*$条件,则它将返回空字符串,否则它将返回单个空格字符串。这就是匹配被替换为返回值。

答案 2 :(得分:0)

您可以使用str.translate方法,该方法比regex更快:

>>> import string
>>> s ='aslkdf -  sadlk#gjf'
>>> s.translate(str.maketrans(string.punctuation,32*' ','-'+string.whitespace))
'aslkdfsadlk gjf'

答案基准:

#Avinash Raj
:~$ python3 -m timeit "import re;s='aslkdf -  sadlk#gjf';re.sub(r'\W+', lambda m: '' if re.match(r'\s*-\s*$', m.group(0)) else ' ', s)"
100000 loops, best of 3: 7.96 usec per loop
#Kasra
:~$ python3 -m timeit "import string;s='aslkdf -  sadlk#gjf';s.translate(str.maketrans(string.punctuation,32*' ','-'+string.whitespace))"
100000 loops, best of 3: 4.75 usec per loop
#user 5061
:~$ python3 -m timeit "import re;s='aslkdf -  sadlk#gjf';s=s.lower();s = re.sub(r'([a-z])-([a-z])', r'\1\2', s);re.split(r'[^a-z]', s)"
100000 loops, best of 3: 8.46 usec per loop