本文介绍了Python对于正则表达式的支持,包括正则表达式基础以及Python正则表达式标准库的完整介绍及使用示例。本文的内容不包括如何编写高效的正则表达式、如何优化正则表达式,这些主题请查看其他教程。
注意:本文基于Python2.4完成;如果看到不明白的词汇请记得百度谷歌或维基,whatever。
尊重作者的劳动,转载请注明作者及原文地址 >.<html
最短匹
正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同;但不用担心,不被支持的语法通常是不常用的部分。如果已经在其他语言里使用过正则表达式,只需要简单看一看就可以上手了。
下图展示了使用正则表达式进行匹配的流程:
正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,看下图中的示例以及自己多使用几次就能明白。
下图列出了Python支持的正则表达式元字符和语法:
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"。
Jeffrey: 我加一点自己做项目过程中遇到的这种匹配方式的理解:
最短匹配:.*? http://deerchao.net/tutorials/regex/regex.htm
假如,我们有以下的代码存放在Test_1.xml中(注意:这里不仅限于xml文件,同样的也适应于其它的任何的文件):我们的
要匹配到原文件中的下列内容
<pre name="code" class="html"><span style="color:#FF0000;"><Response Status="OKAY" CongLvl="LEVEL0" OverallProvTime="4026852" TimeInReqQueue="228" DbCommitTime="6371" RequestId="100000">
<CapacityParms>
<Category>RESIDENTIALSUBSCRIBER_R2</Category>
<FeatureSetName>R1 FEATURE SET</FeatureSetName>
<OfficeId>ylvJrPbcGgHE</OfficeId>
<CurrentCnt>0</CurrentCnt>
<LimitCnt>0000050</LimitCnt>
<SpareCapacity>0</SpareCapacity>
<TasUnequalDistribution>0</TasUnequalDistribution>
</CapacityParms>
</Response></span>
这个是我的re_test.py代码文件,这个文件中到了两种匹配方式,当然,只有def re_testsearch()才可以满足我们的要求,因为它是实现的是段落匹配(因为这个里面用了
re.S)
#-*- coding:utf-8 -*-
#最上一句如果不加上的话不能输入汉字,不然编译不过
#/usr/bin/python
import os
import sys
import re
####################################################
# 一行一行的匹配
# 比如Test_2.xml中的内容如下:
# <Response Staus="OKAY" CongLvl="jeffrey">
# <a>test1</a>
# <b>test2</b>
# </Response>
# <Response Staus="OKAY" CongLvl="guan">
# <a>test1</a>
# <b>test2</b>
# </Response>
# <Response Staus="OKAY" CongLvl="zenghui">
# <a>test1</a>
# <b>test2</b>
# </Response>
# <Response Staus="OKAY" CongLvl="jeguan">
# <a>test1</a>
# <b>test2</b>
# </Response>
# 那么匹配后的得到结果为
# <Response Staus="OKAY" CongLvl="jeffrey">
# <Response Staus="OKAY" CongLvl="guan">
# <Response Staus="OKAY" CongLvl="zenghui">
# <Response Staus="OKAY" CongLvl="jeguan">
#
####################################################
def re_test():
# 原文件
filename = r'C:\Users\jeguan\Desktop\Test_2.xml'
# 匹配得到的内容存储在Test_2_bk.xml中
new_file = r'C:\Users\jeguan\Desktop\Test_2_bk.xml'
# 打开原文件
open_file = open(filename, 'r')
read_file = open_file.readlines()
# 打开目标文件,即:存放匹配结果的文件
newfile = open(new_file, 'wb')
# 匹配以<Response开头并且有CongLvl字符串的行,注意,
# 这里是非lazzy匹配,并且是一行一行匹配,即,遇到
# '\n'就会结束
patt = re.compile(r'^<Response.*CongLvl.*')
# 遍历原文件的所有行,如果找到就会存盘
for line in read_file:
match = patt.search(line)
if match:
m = match.group(0)
newfile.write(m)
open_file.close()
newfile.close()
#################################################################################
# 多行匹配,即:可以匹配一个文本中的特定段落。这里主要是要用到re模块中的re.S
# 它表示当用'.'来进行匹配的时候,可以忽略掉'\n',这一点与'.'正常的规则是不一样的
#
# 另外一个要注意的地方是这里使用了Lazzy匹配的方式。当有多个Response>出现的时候,
# 它只会匹配第一次出现的地方。比如:
# <Response Staus="OKAY" CongLvl="jeguan">
# <a>test1</a>
# <b>test2</b>
# </Response>
# <Response Staus="OKAY" CongLvl="zenghuiguan">
# <a>test3</a>
# <b>test4</b>
# </Response>
# 当用lazzy方式的时候,只会匹配到第一次出现Response>的地方
# 本文中匹配得到的结果为:
# <Response Staus="OKAY" CongLvl="jeguan">
# <a>test1</a>
# <b>test2</b>
# </Response>
#
################################################################################
def re_testsearch():
#
filename = r'C:\Users\jeguan\Desktop\Test_2.xml'
new_file = r'C:\Users\jeguan\Desktop\Test_2_bk.xml'
open_file = open(filename, 'r')
read_file = open_file.readlines()
newfile = open(new_file, 'wb')
# re.S means: Make the '.' special character match any character at all,
# including a newline; without this flag, '.' will match anything except a newline.
# '(.+?)' means: this is a greedy match. When the fist 'Response>' is found, then
# it will not try to match the next 'Response>'
<span style="color:#CC0000;">patt = re.compile(r'<Response Status="OKAY" CongLvl="LEVEL0"*(.+?)Response>', <strong>re.S</strong>)</span>
str1 = ""
# 把读出的行放在str1中
for line in read_file:
str1 = str1 + line
match1 = patt.search(str1)
newfile.write(match1.group(0))
print(match1.group())
if __name__ == "__main__":
re_testsearch()
我们用re_testsearch()这个函数来匹配最终的结果如下所示,得到了我们的要求:
<Response Status="OKAY" CongLvl="LEVEL0" OverallProvTime="4026852" TimeInReqQueue="228" DbCommitTime="6371" RequestId="100
<CapacityParms>
<Category>RESIDENTIALSUBSCRIBER_R2</Category>
<FeatureSetName>R1 FEATURE SET</FeatureSetName>
<OfficeId>ylvJrPbcGgHE</OfficeId>
<CurrentCnt>0</CurrentCnt>
<LimitCnt>0000050</LimitCnt>
<SpareCapacity>0</SpareCapacity>
<TasUnequalDistribution>0</TasUnequalDistribution>
</CapacityParms>
</Response>
但是,如果我们使用re_test()来试图匹配的话,不会得到上面的这个结果,相反,只会找到
<Response Status="OKAY" CongLvl="LEVEL0" OverallProvTime="4026852" TimeInReqQueue="228" DbCommitTime="6371" RequestId="100000">
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等,这部分内容将在Pattern类的工厂方法re.compile(pattern[, flags])中一起介绍。
Python通过re模块提供对正则表达式的支持。使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# encoding: UTF-8
import
re
# 将正则表达式编译成Pattern对象
pattern
=
re.
compile
(r
'hello'
)
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match
=
pattern.match(
'hello world!'
)
if
match:
# 使用Match获得分组信息
print
match.group()
### 输出 ###
# hello
|
re.compile(strPattern[, flag]):
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。 第二个参数flag是匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。
可选值有:
1
2
3
4
|
a
=
re.
compile
(r
"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits"""
, re.X)
b
=
re.
compile
(r
"\d+\.\d*"
)
|
re提供了众多模块方法用于完成正则表达式的功能。这些方法可以使用Pattern实例的相应方法替代,唯一的好处是少写一行re.compile()代码,但同时也无法复用编译后的Pattern对象。这些方法将在Pattern类的实例方法部分一起介绍。如上面这个例子可以简写为:
1
2
|
m
=
re.match(r
'hello'
,
'hello world!'
)
print
m.group()
|
re模块还提供了一个方法escape(string),用于将string中的正则表达式元字符如*/+/?等之前加上转义符再返回,在需要大量匹配元字符时有那么一点用。
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:
方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import
re
m
=
re.match(r
'(\w+) (\w+)(?P<sign>.*)'
,
'hello world!'
)
print
"m.string:"
, m.string
print
"m.re:"
, m.re
print
"m.pos:"
, m.pos
print
"m.endpos:"
, m.endpos
print
"m.lastindex:"
, m.lastindex
print
"m.lastgroup:"
, m.lastgroup
print
"m.group(1,2):"
, m.group(
1
,
2
)
print
"m.groups():"
, m.groups()
print
"m.groupdict():"
, m.groupdict()
print
"m.start(2):"
, m.start(
2
)
print
"m.end(2):"
, m.end(
2
)
print
"m.span(2):"
, m.span(
2
)
print
r
"m.expand(r'\2 \1\3'):"
, m.expand(r
'\2 \1\3'
)
### output ###
# m.string: hello world!
# m.re: <_sre.SRE_Pattern object at 0x016E1A38>
# m.pos: 0
# m.endpos: 12
# m.lastindex: 3
# m.lastgroup: sign
# m.group(1,2): ('hello', 'world')
# m.groups(): ('hello', 'world', '!')
# m.groupdict(): {'sign': '!'}
# m.start(2): 6
# m.end(2): 11
# m.span(2): (6, 11)
# m.expand(r'\2 \1\3'): world hello!
|
Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。
Pattern不能直接实例化,必须使用re.compile()进行构造。
Pattern提供了几个可读属性用于获取表达式的相关信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import
re
p
=
re.
compile
(r
'(\w+) (\w+)(?P<sign>.*)'
, re.DOTALL)
print
"p.pattern:"
, p.pattern
print
"p.flags:"
, p.flags
print
"p.groups:"
, p.groups
print
"p.groupindex:"
, p.groupindex
### output ###
# p.pattern: (\w+) (\w+)(?P<sign>.*)
# p.flags: 16
# p.groups: 3
# p.groupindex: {'sign': 3}
|
实例方法[ | re模块方法]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# encoding: UTF-8
import
re
# 将正则表达式编译成Pattern对象
pattern
=
re.
compile
(r
'world'
)
# 使用search()查找匹配的子串,不存在能匹配的子串时将返回None
# 这个例子中使用match()无法成功匹配
match
=
pattern.search(
'hello world!'
)
if
match:
# 使用Match获得分组信息
print
match.group()
### 输出 ###
# world
|
1
2
3
4
5
6
7
|
import
re
p
=
re.
compile
(r
'\d+'
)
print
p.split(
'one1two2three3four4'
)
### output ###
# ['one', 'two', 'three', 'four', '']
|
1
2
3
4
5
6
7
|
import
re
p
=
re.
compile
(r
'\d+'
)
print
p.findall(
'one1two2three3four4'
)
### output ###
# ['1', '2', '3', '4']
|
1
2
3
4
5
6
7
8
|
import
re
p
=
re.
compile
(r
'\d+'
)
for
m
in
p.finditer(
'one1two2three3four4'
):
print
m.group(),
### output ###
# 1 2 3 4
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
re
p
=
re.
compile
(r
'(\w+) (\w+)'
)
s
=
'i say, hello world!'
print
p.sub(r
'\2 \1'
, s)
def
func(m):
return
m.group(
1
).title()
+
' '
+
m.group(
2
).title()
print
p.sub(func, s)
### output ###
# say i, world hello!
# I Say, Hello World!
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
re
p
=
re.
compile
(r
'(\w+) (\w+)'
)
s
=
'i say, hello world!'
print
p.subn(r
'\2 \1'
, s)
def
func(m):
return
m.group(
1
).title()
+
' '
+
m.group(
2
).title()
print
p.subn(func, s)
### output ###
# ('say i, world hello!', 2)
# ('I Say, Hello World!', 2)
|
以上就是Python对于正则表达式的支持。熟练掌握正则表达式是每一个程序员必须具备的技能,这年头没有不与字符串打交道的程序了。笔者也处于初级阶段,与君共勉,^_^
另外,图中的特殊构造部分没有举出例子,用到这些的正则表达式是具有一定难度的。有兴趣可以思考一下,如何匹配不是以abc开头的单词,^_^
全文结束
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法