python的python re正则表达式式可以选择从单词的第二个字母开始匹配么?

一. 判断字串是否全部为小写字母
二. 找出句子中缩写词的全拼
三. 把数字中的逗号(例如123,345,000)去掉
四. 中文处理之年份转换(例如:一九四九年---&1949年)
会用到的语法
前面元素至少出现一次
ab+:ab、abbbb 等
前面元素出现0次或多次
ab*:a、ab、abb 等
匹配前面的一次或0次
Ab?: A、Ab 等
作为开始标记
^a:abc、aaaaaa等
作为结束标记
c$:abc、cccc 等
3、4、9 等
A、a、- 等
A到z之间的任意字母
a、p、m 等
0到9之间的任意数字
0、2、9 等
1. 转义字符
'(abc)def'
&&& m = re.search("(\(.*\)).*", s)
&&& print m.group(1)
group()用法
2. 重复前边的字串多次
&&& a = "kdlal123dk345"
&&& b = "kdlal123345"
&&& m = re.search("([0-9]+(dk){0,1})[0-9]+", a)
&&& m.group(1), m.group(2)
('123dk', 'dk')
&&& m = re.search("([0-9]+(dk){0,1})[0-9]+", b)
&&& m.group(1)
&&& m.group(2)
一. 判断字符串是否是全部小写
# -*- coding: cp936 -*-
s1 = 'adkkdk'
s2 = 'abc123efg'
an = re.search('^[a-z]+$', s1)
print 's1:', an.group(), '全为小写'
print s1, "不全是小写!"
an = re.match('[a-z]+$', s2)
print 's2:', an.group(), '全为小写'
print s2, "不全是小写!"
1. 正则表达式不是python的一部分,利用时需要引用re模块
2. 匹配的形式为: re.search(正则表达式, 带匹配字串)或re.match(正则表达式, 带匹配字串)。两者区别在于后者默认以开始符(^)开始。因此,
re.search('^[a-z]+$', s1) 等价于 re.match('[a-z]+$', s2)
3. 如果匹配失败,则an = re.search('^[a-z]+$', s1)返回None
group用于把匹配结果分组
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)
#123abc456,返回整体
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)
1)正则表达式中的三组括号把匹配结果分成三组
  group() 同group(0)就是匹配正则表达式整体结果
  group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。
2)没有匹配成功的,re.search()返回None
3)当然郑则表达式中没有括号,group(1)肯定不对了。
二. &首字母缩写词扩充
Federal Emergency Management Agency
Irish Republican Army
Democratic Unionist Party
Food and Drug Administration
Office of Legal Counsel
缩写词  FEMA
分解为  F*** E*** M*** A***
大写字母 + 小写(大于等于1个)+ 空格
def expand_abbr(sen, abbr):
lenabbr = len(abbr)
for i in range(0, lenabbr):
ma += abbr[i] + "[a-z]+" + ' '
print 'ma:', ma
ma = ma.strip(' ')
p = re.search(ma, sen)
return p.group()
print expand_abbr("Welcome to Algriculture Bank China", 'ABC')
上面代码对于例子中的前3个是正确的,但是后面的两个就错了,因为大写字母开头的词语之间还夹杂着小写字母词
大写字母 + 小写(大于等于1个)+ 空格 + [小写+空格](0次或1次)
def expand_abbr(sen, abbr):
lenabbr = len(abbr)
for i in range(0, lenabbr-1):
ma += abbr[i] + "[a-z]+" + ' ' + '([a-z]+ )?'
ma += abbr[lenabbr-1] + "[a-z]+"
print 'ma:', ma
ma = ma.strip(' ')
p = re.search(ma, sen)
return p.group()
print expand_abbr("Welcome to Algriculture Bank of China", 'ABC')
中间的 小写字母集合+一个空格,看成一个整体,就加个括号。要么同时有,要么同时没有,这样需要用到?,匹配前方的整体。
三. 去掉数字中的逗号
在处理自然语言时123,000,000如果以标点符号分割,就会出现问题,好好的一个数字就被逗号肢解了,因此可以先下手把数字处理干净(逗号去掉)。
数字中经常是3个数字一组,之后跟一个逗号,因此规律为:***,***,***
[a-z]+,[a-z]?
参考代码3-1
sen = "abc,123,456,789,mnp"
p = re.compile("\d+,\d+?")
for com in p.finditer(sen):
mm = com.group()
print "hi:", mm
print "sen_before:", sen
sen = sen.replace(mm, mm.replace(",", ""))
print "sen_back:", sen, '\n'
使用函数finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。 & & &
参考代码3-2
sen = "abc,123,456,789,mnp"
mm = re.search("\d,\d", sen)
mm = mm.group()
sen = sen.replace(mm, mm.replace(",", ""))
这样的程序针对具体问题,即数字3位一组,如果数字混杂与字母间,干掉数字间的逗号,即把&abc,123,4,789,mnp&转化为&abc,1234789,mnp&
更具体的是找正则式&数字,数字&找到后用去掉逗号的替换
参考代码3-3
sen = "abc,123,4,789,mnp"
mm = re.search("\d,\d", sen)
mm = mm.group()
sen = sen.replace(mm, mm.replace(",", ""))
四. 中文处理之年份转换(例如:一九四九年---&1949年)
中文处理涉及到编码问题。例如下边的程序识别年份(****年)时
# -*- coding: cp936 -*-
"在一九四九年新中国成立"
"比一九九零年低百分之五点二"
'人一九九六年击败俄军,取得实质独立'
def fuc(m):
a = re.findall("[零|一|二|三|四|五|六|七|八|九]+年", m)
for key in a:
print "NULL"
可以看出第二个、第三个都出现了错误。
改进&&准化成unicode识别
# -*- coding: cp936 -*-
"在一九四九年新中国成立"
"比一九九零年低百分之五点二"
m2 = '人一九九六年击败俄军,取得实质独立'
def fuc(m):
m = m.decode('cp936')
a = re.findall(u"[\u96f6|\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d]+\u5e74", m)
for key in a:
print "NULL"
识别出来可以通过替换方式,把汉字替换成数字。
numHash = {}
numHash['零'.decode('utf-8')] = '0'
numHash['一'.decode('utf-8')] = '1'
numHash['二'.decode('utf-8')] = '2'
numHash['三'.decode('utf-8')] = '3'
numHash['四'.decode('utf-8')] = '4'
numHash['五'.decode('utf-8')] = '5'
numHash['六'.decode('utf-8')] = '6'
numHash['七'.decode('utf-8')] = '7'
numHash['八'.decode('utf-8')] = '8'
numHash['九'.decode('utf-8')] = '9'
def change2num(words):
print "words:",words
newword = ''
for key in words:
if key in numHash:
newword += numHash[key]
newword += key
return newword
def Chi2Num(line):
a = re.findall(u"[\u96f6|\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d]+\u5e74", line)
print "------"
print line
for words in a:
newwords = change2num(words)
print words
print newwords
line = line.replace(words, newwords)
return line
阅读(...) 评论()python的正则表达式可以选择从单词的第二个字母开始匹配么?_百度知道
python的正则表达式可以选择从单词的第二个字母开始匹配么?
如题目,比如是否可以从一个单词的第二个字母以后匹配元音?
mprint&)n&)print&rep1&asd 匹配失败;re.search('m&p1;)&=&asd'=&nbsp.search(&#39.SRE_Match object at 0x&=&&pile(r'^[a-z][aeiou][a-z]*'_nresult--------------------------None&p1;desk&#39import&nbsp
额...我的意思是 比如从 phone这个单词的h字母开始匹配元音的话,应该怎么限定它的匹配范围?
^[a-z][aeiou][a-z]*^代表从第一个字母开始匹配你想要从第二个开始匹配嘛,所以第一个就是[a-z],第二个就是[aeiou]*代表匹配上一个字符 0 到n次
其他类似问题
正则表达式的相关知识
按默认排序
其他1条回答
一切皆有可能
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁您所在的位置: &
正则表达式匹配单词细节解析
正则表达式匹配单词细节解析
正则表达式匹配单词是如何实现的呢,这里我们向你介绍了一个详细的实施办法以及实现的原理分析,希望对你了解正则表达式匹配单词有所帮助。
正则表达式匹配单词其实就是要处理单词的边界问题,那么具体的实现是如何呢?正则表达式匹配单词所涉及的方法以及原理是什么呢?那么让我们开始吧
正则表达式匹配单词的内幕:
元字符&&\b&&也是一种对位置进行匹配的“锚”。这种匹配是0长度匹配。有4种位置被认为是“单词边界”:
1)在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)
2)在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)
3)在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后
4)在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面
“单词字符”是可以用“\w”匹配的字符,“非单词字符”是可以用“\W”匹配的字符。在大多数的正则表达式实现中,“单词字符”通常包括&&[a-zA-Z0-9_]&&。
例如:&&\b4\b&&能够匹配单个的4而不是一个更大数的一部分。这个正则表达式不会匹配“44”中的4。
换种说法,几乎可以说&&\b&&匹配一个“字母数字序列”的开始和结束的位置。
“单词边界”的取反集为&&\B&&,他要匹配的位置是两个“单词字符”之间或者两个“非单词字符”之间的位置。
正则表达式匹配单词的原理探讨:
◆深入正则表达式引擎内部
让我们看看把正则表达式&&\bis\b&&应用到字符串“This island is beautiful”。引擎先处理符号&&\b&&。因为\b是0长度 ,所以第一个字符T前面的位置会被考察。因为T是一个“单词字符”,而它前面的字符是一个空字符(void),所以\b匹配了单词边界。接着&&i&&和第一个字符“T”匹配失败。匹配过程继续进行,直到第五个空格符,和第四个字符“s”之间又匹配了&&\b&&。然而空格符和&&i&&不匹配。继续向后,到了第六个字符“i”,和第五个空格字符之间匹配了&&\b&&,然后&&is&&和第六、第七个字符都匹配了。然而第八个字符和第二个“单词边界”不匹配,所以匹配又失败了。到了第13个字符i,因为和前面一个空格符形成“单词边界”,同时&&is&&和“is”匹配。引擎接着尝试匹配第二个&&\b&&。因为第15个空格符和“s”形成单词边界,所以匹配成功。引擎“急着”返回成功匹配的结果。
【编辑推荐】
【责任编辑: TEL:(010)】
关于的更多文章
从今天起将开始的这个系列来自一位宅男程序员,这个系列是他写给
网友评论TOP5
本次的专刊为大家提供了Oracle最新推出的Java SE 8详细的开发教程,从解读到探究Java 8最新
从今天起将开始的这个系列来自一位宅男程序员,这个系
jstack--如果java程序崩溃生成core文件,jstack工具可
Play Framework是一个Rails风格full-stack(全栈的)J
本书是一本介绍Windows系统上的用户态程序排错方法和技巧的书。本书分为4个章节,先介绍最重要的、通用的思考方法,以便制定排错
51CTO旗下网站Python下的正则表达式原理和优化
最近的时间内对正则表达式进行了一点点学习。所选教材是《mastering regular expressions》,也就是所谓的《精通正则表达式》。读过一遍后,顿感正则表达式的强大和精湛之处。其中前三章
最近的时间内对正则表达式进行了一点点学习。所选教材是《mastering regular expressions》,也就是所谓的《精通正则表达式》。读过一遍后,顿感正则表达式的强大和精湛之处。其中前三章是对正则表达式的基本规则的介绍和铺垫。七章以后是对在具体语言下的应用。而核心的部分则是四五六这三章节。
其中第四章是讲了整个正则表达式的精华,即传统引擎NFA的回溯思想。第五章是一些例子下对回溯思想的理解。第六章则是对效率上的研究。根源也是在回溯思想上的引申和研究。
这篇文章是我结合python官方re模块的文档以及这本书做一个相应的总结。
其中官方的文档: http://docs.python.org/3.3/library/re.html
由于我都是在python上联系和使用的,所以后面的问题基本都是在python上提出来的,所以这本书中的其它正则流派我均不涉及。依书中,python和perl风格差不多,属于传统NFA引擎,也就是以&表达式主导&,采用回溯机制,匹配到即停止( 顺序敏感,不同于POSIX NFA等采用匹配最左最长的结果)。
对于回溯部分,以及谈及匹配的时候,将引擎的位置总是放在字符和字符之间,而不是字符本身。比如^对应的是第一个字符之前的那个&空白&位置。
基础规则的介绍
中的转义符号干扰
python中,命令行和脚本等,里面都会对转义符号做处理,此时的字符串会和正则表达式的引擎产生冲突。即在python中字符串'\n'会被认为是换行符号,这样的话传入到re模块中时便不再是&\n&这字面上的两个符号,而是一个换行符。所以,我们在传入到正则引擎时,必须让引擎单纯的认为是一个'\'和一个'n',所以需要分别加上转义符,成为'\\\n',针对这个情况,python中使用raw_input方式,在字符串前加上r,使字符串中的转义符不再特殊处理(即python中不处理,统统丢给正则引擎来处理),那么换行符就是r'\n'
#普通模式下,匹配除换行符外的任意字符。(指定DOTALL标记以匹配所有字符)
量词限定符
#匹配前面的对象0个或多个。千万不要忽略这里的0的情况。
#匹配前面的对象1个或多个。这里面的重点是至少有一个。
#匹配前面的对象0个或1个。
#匹配前面的对象m次
#匹配前面的对象最少m次,最多n次。
#匹配字符串开头位置,MULTILINE标记下,可以匹配任何\n之后的位置
#匹配字符串结束位置,MULTILINE标记下,可以匹配任何\n之前的位置
正则引擎内部的转义符号
m是数字,所谓的反向引用,即引用前面捕获型括号内的匹配的对象。数字是对应的括号顺序。
只匹配字符串开头
可以理解一个锚点的符号,此符号匹配的是单词的边界(&单词边界符&)。这其中的word定义为连续的字母,数字和下划线。
准确的来说,\b的位置是在\w和\W的交界处,当然还有字符串开始结束和\w之间。
和\b对应,本身匹配空字符,但是其位置是在非&边界&情况下,比如r'py\B'可以匹配python,但不能匹配'py,','py.' 等等
匹配非数字
未指定UNICODE和LOCALE标记时,等同于[ \t\n\r\f\v],注意\t之前是一个空格,表示也匹配空格。
未指定UNICODE和LOCALE标记时,等同于[a-zA-Z0-9_]
只匹配字符串的结尾
其他的一些python支持的转移符号也都有支持,如前面的'\t'
尤其注意,这个字符集最终 只匹配一个字符(既不是空,也不是一个以上)!所以,前面的一些量词限定符,在这里失去了原有的意义。
另外,'-'符号放在两个字符之间的时候,表示ASCII字符之间的所有字符,如[0-9],表示0到9.
而当放在字符集开头或者结尾,或者被'\'转义时候,则只是表示特指'-'这个符号
最后,当在开头的地方使用'^',表示排除型字符组.
括号的相关内容
普通型括号
普通捕获型括号,可以被\number引用。
扩展型括号
#忽略大小写
#点号匹配包括换行符
#可以多行写表达式
(?:......)
#非捕获型括号,此括号不记录捕获内容,可节省空间
(?P&name&...)
#此捕获型括号可以使用name来调用,而不必依赖数字。调用时使用(?P=name)
#注释型括号,此括号完全被忽略
#lookahead assertion 如果后面是括号中的,则匹配成功
#negative lookahead assertion
如果后面不是括号中的,则匹配成功
#positive lookbehind assertion
如果前面是括号中的,则匹配成功
#negative lookbehind assertion
如果前面不是括号中的,则匹配成功
#以上&span&&b&四种类型断言&/b&&/span&,本身均不匹配内容,只是告知正则引擎是否开始匹配或者停止。
#另外在后两种后项断言中,必须为&b&定长断言&/b&。
(?(id/name)yes-pattern|no-pattern)
#如有由id或者name指定的组存在的话,将会匹配yes-pattern,否则将会匹配no-pattern,通常情况下no-pattern也可以省略。
匹配优先/忽略优先符号
在量词限定符中,默认的情况都是匹配优先,也就是说,在符合条件的情况下,正则引擎会尽量匹配多的字符( 贪婪规则)
在这些符号后面加上'?',则正则引擎会成为忽略优先,此时的正则引擎会优先匹配 尽可能少的情况。
如'??'会优先匹配没有的情况,然后才是1个对象的情况。而{m,n}?则是优先匹配m个对象,而不是占多的n个对象。
相关进阶知识
首先放在最前面,python属于perl风格,属于传统型NFA引擎,与此相对的是POSIX NFA和DFA。所以大部分讨论都针对传统型NFA
传统型NFA中的顺序问题
NFA是基于正则表达式主导的引擎,同时,传统型NFA引擎会在找到符合状态的情况下立即停止。即得到匹配之后就停止引擎。相对来说,POSIX NFA 中不会立刻停止,其会在所有可能匹配的结果中寻求最长结果。这也是有些bug在传统型NFA中不会出现,但是放到后者中,会出现无法结束的情况。
引申一点,NFA学名为&非确定型有穷自动机&,DFA学名为&确定型有穷自动机&
这里的非确定和确定均是指被匹配的目标文本中的字符来说的,在NFA中,每个字符在一次匹配中即使被检测通过,也不能确定他是否真正通过,因为NFA中会出现回溯!甚至不止一两次。图例见后面例子。而在DFA中,由于是目标文本主导,所有对象字符只检测一遍,到文本结束后,过就是过,不过就不过。这也就是&确定&这个词的来历。
回溯/备用状态
当出现可选分支时,会将其他的选项存储起来,作为备用状态。当前的匹配失败时,引擎进行回溯,则会回到最近的备用状态。
匹配的情况中,匹配优先与忽略优先某种意义上是一致的,只是顺序上有所区别。当存在多个匹配时,两种方式进行的情况很可能是不同的,但是当不存在匹配时,他们俩的情况是一致的,即必然尝试了所有的可能。
回溯机制两个要点
在是进行尝试还是跳过尝试时,匹配优先量词和忽略优先量词会作出相应决定。
匹配失败时,回溯需要返回到上一个备用状态,原则是后进先出(LIFO)
回溯典型举例:
这里可以看到,传统型NFA到D点即匹配结束。而在POSIX NFA中,需要找到所有结果,并在这些结果中取最长的结果返回。
当无法出现匹配时,如下图,我们看到POSIX NFA和传统型NFA的匹配路径是一致的。
以上的例子引发了一个匹配时的思考,我们尽量避免使用'.*' ,因为其总是可以匹配到最末或者行尾,既然我们只寻求引号之间的数据,往往可以借助排除型数组来完成工作。此例中,使用'[^'']*'这个的作用显而易见,我们只匹配非引号的内容,那么遇到第一个引号即可退出*号控制权。
固化分组思想
固化分组的思想很重要, 但是python中并不支持。即在使用(?&...)括号中的匹配时产生的备选状态一旦离开括号,便会被引擎抛弃掉。举个典型的例子如:
'\w+:'
这个匹配的情况是这样的,会优先去匹配所有的符合\w的字符,然后假如字符串的末尾没有:,即匹配未找到冒号,此时触发回溯机制,他会迫使前面的\w+释放字符,并且在交还的字符中重新尝试与':'作比对。但是问题出现在\w是不包含冒号的,显然无论如何都不会匹配成功,但是依照回溯机制,就会造成无谓的比对,这是对资源的浪费。所以我们就需要避免这种回溯,对此的方法就是将前面匹配到的内容固化,不令其存储备用状态,那么引擎就会因为没有备用状态可用而结束匹配过程。大大减少回溯的次数。
模拟固化过程
虽然python中不支持,但书中提供了利用前向断言来模拟固化过程。
(?=(...))\1
这里注意的是断言中的结果是不会保存备用状态的,虽然他本身不匹配内容,但是可以巧妙的添加一个捕获型括号来利用反向引用来达到此效果。对应上面的例子则是:
'(?=(\w+))\1:'
多选结构在传统型NFA中, 既不是匹配优先也不是忽略优先。而是按照顺序进行的。这样就更可以很好的利用此特点进行调试。
在相对的应用中,在结果保证正确的情况下,应该优先的去匹配更可能出现的结果。即将可能性大的分支尽可能放在靠前。
多选结构的代价。不能滥用多选结构,因为当匹配到多选结构时,缓存会记录下相应数目的备用状态。举例子如:[abcdef]和&a|b|c|d|e|f&这两个表达式很可能经过稍稍修改都能完成你的某个任务,但是尽量选择字符型数组,显然后者会在每次比较时建立6个备用状态,会占用一定的内存。
一些优化的理念和技巧
好的正则表达式需寻求如下平衡:
只匹配期望的文本,排除不期望的文本。(善于使用非捕获型括号)
必须易于控制和理解
使用NFA引擎,必须保证效率(如果能够匹配,必须很快地返回匹配结果,如果不能匹配,应该在尽可能短的时间内报告匹配失败。)
处理不期望的匹配
在处理过程中,我们总是习惯于使用星号等非硬性规定的量词,可能我们使用的匹配表达式中没有必须匹配的字符,如量词均为'?','*'等,那么其结果必然会出现不可控,这是我们必须需要处理的。
对数据的了解和假设
其实在处理很多数据的时候,我们的操作数据情况都是不一样的,有时会很规整,那么我们可以省掉考虑复杂表达式的情况,但是反过来,就需要思考多一些,对各种可能的情形做相应的处理。
引擎中一般存在的优化项
反复使用编译对象时,应该在使用前,使用re.compile()方法来进行编译,这样在后面调用时不必每次重新编译。节省时间。尤其是在循环体中反复调用正则匹配时。
锚点优化:
配合一些引擎的优化,应尽量将锚点单独凸显出来。对比^a|^b,其效率便不如^(a|b)
同样的道理,系统也会处理行尾锚点优化。所以在写相关正则时,如果有可能的话,将锚点使用出来。
引擎中的优化,会对如.* 这样的量词进行统一对待,而不是按照传统的回溯规则,所以,从理论上说'(?:.)*' 和'.*'是等价的,不过具体到引擎实现的时候,则会对'.*'进行优化。速度就产生了差异。
消除不必要括号以及字符组
这个在python中是否有 未知。只是在支持的引擎中,会对如[.]中转化成\.,因为显然后者的效率更高(字符组处理引起额外开销)
以上是一些引擎带的优化,自然实际上是我们无法控制的的,不过了解一些后,对我们后面的一些处理和使用有很大帮助。
其他技巧和补充内容
过度回溯问题
消除指数级匹配
形如下面:
这种情况的表达式,在匹配长文本的时候,会遇到什么问题呢,如果在文本匹配失败时(意味着如果失败,则说明已经回溯了 所有的可能),想象一下,*号退一个状态,里面的+号就包括其余的所有状态,验证后,回到外面,*号退到倒数第二个备用状态,再回去,+号又要回溯一边比上一轮差1的备用状态数,当字符串很长时,就会出现指数级的回溯总数。系统就会'卡死'。甚至当有匹配时,这个匹配藏在回溯总数的中间时,也是会造成卡死的情况。所以,使用NFA的引擎时,必须要注意这个问题。
我们采用如下思路去避免这个问题:
占有优先量词(python中使用前向断言加反向引用模拟)
道理很简单,既然庞大的回溯数量都是被储存的备用状态导致的,那么我们直接使引擎放弃这些状态
re_lx = re.compile(r'(?=(\w+))\1*\d')
效率测试代码
在测试表达式的效率时,可借助以下代码比较所需时间。
import time
re_lx1 = re.compile(r'your_re_1')
re_lx2 = re.compile(r'your_re_2')
starttime = time.time()
repeat_time = 100
for i in range(repeat_time):
s='test text'*10000
result = re_lx1.search(s)
time1 = time.time()-starttime
print(time1)
starttime = time.time()
for i in range(repeat_time):
s='test text'*10000
result = re_lx2.search(s)
time2 = time.time()-starttime
print(time2)
量词等价转换
现在来看看大括号量词的效率问题
1,当大括号修饰的对象是类似于字符数组或者\d这种非确定性字符时,使用大括号效率高于重复叠加对象。即:
\d{5}优于\d\d\d\d\d
经测试在python中后者优于前者。会快很多.
2,但是当重复的字符时确定的某一个字符时,则简单的重复叠加对象的效率会高一些。这是因为引擎会对单纯的字符串内部优化(虽然我们不知道具体优化是如何做到的)
aaaaa 优于a{5}
总体上说'\d' 肯定是慢于'1'
我使用的python3中的re模块,经测试,不使用量词会快。
锚点优化的利用
下面这个例子,在我们可以估计到的文本中,假设出现匹配的内容在字符串对象的结尾,那么我们利用如下第一个表达式是快于第二个表达式的,原因在于前者有锚点的优势。
re_lx1 = re.compile(r'\d{5}$')
re_lx2 = re.compile(r'\d{5}')
排除型数组的利用
继续上面的例子,我们发现\w是包含\d的,当使用匹配优先时,前面的\w会掠过数字,之所以能匹配成功,或者确定失败,是后面的\d迫使前面的量词交还一些字符。
知道这一点,我们应该尽量避免回溯,一个顺其自然的想法就是不让前面的匹配优先量词涉及到\d
re_lx1 = re.compile(r'^\w+(\d{5})')
re_lx2 = re.compile(r'^[^\d]+\d{5}')
#优于上面的表达式
在我们没有时间去深入研究模块代码的时候,只能通过尝试和反复修改来得到最终的复合预期的表达式。
常识优化措施
然而我们利用可能的提升效果去尝试修改的时候很有可能 适得其反 , 因为某些我们看来缓慢的回溯在正则引擎内部会进行一定的优化 ,&取巧&的修改又可能会关闭或者避开了这些优化,所以结果也许会令我们很失望。
以下是书中提到的一些 常识性优化措施:
避免重新编译(循环外创建对象)
使用非捕获型括号(节省捕获时间和回溯时状态的数量)
善用锚点符号
不滥用字符组
提取文本和锚点。将他们从可能的多选分支结构中提取出来,会提取速度。
最可能的匹配表达式放在多选分支前面
避免无休止匹配的核心公式
opening normal*(special normal*)* closing
这个公式 特别用来对于匹配在两个特殊符号内的文本
有如下的三点避免无休止匹配的发生。
special部分和normal部分匹配的开头不能重合。一定保证这两部分在任何情况下不能匹配相同的内容,不然在无法出现匹配时遍历所有情况,此时引擎的路径就不能确定。
normal部分必须匹配至少一个字符
special部分必须是固定长度的
转自:http://my.oschina.net/o0Kira0o/blog/138516
转载请保留链接:
------分隔线----------------------------
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
Python支持多种图形界面的第三方库,包括: Tk wxWidgets Qt GTK 等等...
如果我们要编写一个搜索引擎,第一步是用爬虫把目标网站的页...
PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库...
Python的内建模块 itertools 提供了非常有用的用于操作迭代对象的...
摘要算法简介 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等...
准确地讲,Python没有专门处理字节的数据类型。但由于 str 既是...

我要回帖

更多关于 python正则表达式提取 的文章

 

随机推荐