首页 > 技术文章 > ****正则表达式详解

spidermansam 2017-11-06 18:52 原文

正则表达式,缩写微微regex regexp RE等
正则表达式是处理文本极为重要的技术,用它可以对字符串按照某种规则进行检索
是1970 unix之父ken thompson将正则表达式引入到unix中文本编辑器ed和grep命令中
1980年 perl语言对henry spencer编写的库,扩展了很多新的特性,1997年开始开发出了PCRE,被PHP和HTTPD广泛使用
 
shell中处理文本命令,各种高级编程语言都支持正则表达式
 
BRE
基本正则表达式 grep sed vi等软件支持,,vim有扩展
ERE
扩展正则表达式,egrep ( grep-E ) ,sed - r等
PCRE
几乎所有语言都是PCRE的方言或者变种,python使用SRE正则表达式引擎,可以认为是PCRE的子集,模块为re 
 
基本语法:
 
   元字符
                                   说明
                 举例
.
匹配除换行符外地所有字符
.
[abc]
字符范围,只能匹配一个位置的对应任意一个字符
[abc]匹配plain中的 'a'
[^abc]
字符范围,匹配除指定字符以外的任何一位字符的一个位置
[^abc]匹配plain中的 p l i n 
[a-z]
字符范围,表示任意一个字符的字符位置
常用[a-z][0-9]
\b
匹配单词的边界
\bb在文本中找到单词b开头的b字符
\B
不匹配单词的边界
t\B包含t的单词但是不以t结尾的t字符,例如write
\Bb,不以b开头的含有b的单词,如able
\d
[0-9]匹配1位数字
\d
\D
[^0-9匹配一位非数字
 
\s
匹配1位空白字符,包括换行符,制表符,空格
[\f\r\n\t\v] 
 
 
\S
匹配一位非空白字符
 
\w
匹配[a-z0-9A-Z_],包括中文字符
\w
\W
匹配\w之外的字符
 
单行模式:
.    可以匹配任意字符,包括换行符
^   表示整个字符串的开头,$整个字符串的结尾
 
多行模式:
.    可以匹配除了换行符之外的字符
^   表示行首,$行尾
^   表示整个字符串的开始, ^表示整个字符串的结尾,开始指的是\n后的第一个字符,结束指的是\n前段哪一个字符
windows中 会有\r\n存在,会干扰$的测试
 
转义
凡是在正则表达式中有特殊意义的符号,如果想要使用它的本意,使用 \ 转义,反斜杠自身也可以被转义,使用 \\
\r、\n还是转义后代表回车,换行
 
重复
 
 
代码
                                  说明
                               举例
*
表示前面的正则表达式会重复 0次到多次
e\w*单词中有e然后后面非空白字符
+
表示前面的正则表达式会重复 1次到多次
e\w+单词中有e且后面至少有一个空白字符
?
表示前面的正则表达式会重复 0次到1次
e\w?单词中有e且后面最多有一个空白符
{n}
重复固定的n次
e\w{1}   匹配1次
{n,}
重复n到无限次
e\w{1}   1到无限次
{n,m}
重复n到m的次数 
e\w{1,3} 匹配至少1,至多3次   
 
 
       代码
                                                     说明
                 举例
x|y
匹配x或者y
wood took foot food
使用w|ood或者(w|f)ood
捕获(分组)
 
 
(pattern)
使用小括号指定一个子表达式,也叫分组,捕获后会自动分配组号从1开始可以改变优先级
 
\数字
匹配对应的分组,注意括号后有一个空格
(very)\1 匹配very very,但捕获的组是groupvery
(?:pattern)
如果为了改变优先级,就不需要捕获分组
(?:w|f)ood     例如go(?:od|d)等价于good|god
(?<name>exp)
(?'name'exp)
分组捕获,但是可以通过name访问分组python语法必须是(?P,name>exp)
 
零宽断言
 
 
(?=exp)
断言exp一定在匹配的右边出现
f(?=oo)    f后面一定有oo出现
(?<=exp)
断言匹配左边一定有exp出现
(?<=f)ood     ood左边一定要有f出现
负向零宽断言
 
 
(?!exp)
断言exp一定不会出现在匹配的右侧
\d{3}(?!\d),断言在三位数字后一定不能是数字
(?<!exp)
断言exp一定不出出现在匹配的左侧
(?<!f)ood ood的左边一定不能出现f
注释;
 
 
(?#comment)
注释
f(?=oo)(?#这是个右断言,不分组)
分组和捕获是同一个意思
能用简单的表达式,就不用复杂的表达式
 
贪婪与非贪婪
默认贪婪模式,也就是说尽量多匹配更长的字符串
非贪婪很简单,在重复的符号后面加上一个 ? ,就尽量的少匹配了
 
           代码
                                                                                          说明
*?
匹配任意次,但尽量少重复
+?
最少匹配1次,但尽量少重复
{n,}?
最少匹配n次,但尽量少重复
{n,m}?
最少匹配n次,最多匹配m次,但尽量少重复
 
引擎选项
 
                              代码
                            说明
                             python
IgonreCase
匹配时忽略大小写
re.I
re.IGNORECASE
Singleline
单行模式 : . 可以匹配所有字符,包括\n
re.S
re.DOTALL
Multiline
多行模式:^ 行首 , $行尾
re.M
re.MULTILINE
IgnorePatternWhitespace
忽略表达式中的空白字符,如果要使用空白字符用转移,#可以用来做注释
re.X
re.VERBOSE
如何使用正则匹配ip地址
(?:25[0-5]|2[0-4]\d|[01]?\d\d?\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)
思路: 考虑最大上限,以及两位开头
python的正则表达式
python使用re模块提供了正则表达式
使用python正则匹配,应该先编译,在使用方法,提高效率
 
re.M多行模式
re.S单行
re.I忽略大小写
re.X忽略空白字符
使用 | 位或运算开启多种选项
 
使用方法 (编译)  :
re.compile(pattern,flag=0)  pattern(正则表达式字符串)(flag为选项)
编译:人工编写的正则表达式式电脑执行比较苦难,所以需要对其进行编译,编译后会得到一个正则表达式对象regex,从而提高效率,且re的其他调用达到也提速的效果
 
单次匹配
re.match(pattern,string,flag=0)     未编译
通过re模块对一个字符串由左至右匹配,找到第一个立即返回match对象
 
regex.match(string,pos=0,endpos=-1)  编译过
通过regex对象,对一个字符串由左至右匹配,找到第一个立即返回match对象
 
未编译使用match的缺点,用法单一,只能匹配第一个字符串开头的字符,若匹配项与被匹配的一个字符不符合,就会返回None
编译后使用match可以搭配索引锚定起始,来匹配指定位置
 
re匹配方法二:
search方法
re.search(pattern,string)          未编译
从头开始,由左至右匹配到第一个字符即返回一个match对象,只匹配一次 
 
re.compile(pattern,pos=0,endpos=-1)
regex.match(string)       以编译
从头开始,由左至右匹配到第一个字符即返回一个match对象,只匹配一次
 
re.fullmatch(pattern,string)全长匹配,整个字符串和正则表达式匹配,不满足则返回none
 
全部匹配
re.compile(pattern,pos=0,endpos=-1) 对正则进行编译,编译时可以指定多行或者单行模式   
 
re.findall(pattern,string,flag=0)               未编译
regex.findall(string,pos=0,endpos=-1)     以编译
对整个字符串由左至右匹配,返回所有匹配项的列表   
 
re.finditer(pattern,string,flag=0)               未编译
regex.finditer(string,pos=0,endpos=-1)     以编译
 
对整个字符串由左至右匹配,返回所有匹配项,返回迭代器,可以使用next()来对其进行惰性求值  
每次迭代返回的是match对象       
 
匹配对象替换
 
regex = re.compile('b\wg')
全局替换
re.sub(pattern,replacement,string,count=0,flag=0)
regex.sub(replacement,string,count=0)
使用pattern对字符串string'进行匹配,对匹配项使用repl替换
replacement可以是string,bytes,function
 
re,sub(pattern,replacement,string,count=0,flags=0)
指定替换次数(count=?)
regex.subn(replacement,string,count=0)
同sub返回一个元组
 
字符串分割
字符出啊你的分割函数,不能指定多个字符进行分割
使用re模块进行处理
re.split(pattern,string,maxsplit=0,flag=0)
re.split分割字符串
 
分组
使用小括号的pattern捕获的数据被放到到了组group中
matc search函数可以返回matc对象
 
示例:
log = '''183.60.212.153 - - [19/Feb/2013:10:23:29 +0800] "GET /o2o/media.html?menu=3 HTTP/1.1" 200 16691 "-" "Mozilla/5.0 (compatible; EasouSpider; +http://www.easou.com/search/spider.html)"'''
 
flag=False
lst=[]
tmp =''
#先进性大的切割,拿到一小段
for word in log.split():
  #对这些小段进行边界判断
         if not flag and (word.startswith('[')or word.startswith('"')):
             if word.endswith(']') or word.endswith('"'):
                 #如果找到它的出入口,直接将其加入到 业务列表中,并去掉两头的非法字符
                 lst.append(word.strip('[]"'))
             else:
                 #若找不到它的出口,则打一个印记向后执行
                 tmp += word[1:]
                 flag = True
             continue
             #利用标记进行下一步的处理
         if flag:
             #若在此找到了它的边界
             if word.endswith(']') or word.endswith('"'):
                 #则将tmp的所有字符拼接起来,并追加入lst列表中,重置印记和tmp
                 tmp += '' + word[:-1]
                 lst.append(tmp)
                 flag = False
                 tmp =' '
             else:
                 #若还是没有找到,则继续添加这个字符,直到找到边界为止
                 tmp += ' '+word
             continue
print(lst)

 

 

推荐阅读