正则表达式--import--re--string
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正则表达式--import--re--string相关的知识,希望对你有一定的参考价值。
--********************************************************************************************************************************--import------import string 模块---Python 字符串内置函数--------字符串方法是从python1.6到2.0慢慢加进来的——它们也被加到了Jython中--
--********************************************************************************************************************************
这些方法实现了string模块的大部分方法,如下表所示列出了目前字符串内建支持的方法,所有的方法都包含了对Unicode的支持,有一些甚至是专门用于Unicode的。
string.capitalize() 把字符串的第一个字符大写
string.center(width) 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string.count(str, beg=0, end=len(string)) 返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.decode(encoding='UTF-8', errors='strict') 以 encoding 指定的编码格式解码 string,如果出错默认报一个 ValueError 的 异 常 , 除 非 errors 指 定 的 是 'ignore' 或 者'replace'
string.encode(encoding='UTF-8', errors='strict') 以 encoding 指定的编码格式编码 string,如果出错默认报一个ValueError 的异常,除非 errors 指定的是'ignore'或者'replace'
string.endswith(obj, beg=0, end=len(string)) 检查字符串是否以 obj 结束,如果beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.
string.expandtabs(tabsize=8) 把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8。
string.find(str, beg=0, end=len(string)) 检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
string.format() 格式化字符串
string.index(str, beg=0, end=len(string)) 跟find()方法一样,只不过如果str不在 string中会报一个异常.
string.isalnum() 如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False
string.isalpha() 如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False
string.isdecimal() 如果 string 只包含十进制数字则返回 True 否则返回 False. isdecimal()方法检查字符串是否只包含十进制字符。这种方法只存在于unicode对象。
string.isdigit() 如果 string 只包含数字则返回 True 否则返回 False.
string.islower() 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
string.isnumeric() 如果 string 中只包含数字字符,则返回 True,否则返回 False
string.isspace() 如果 string 中只包含空格,则返回 True,否则返回 False.
string.istitle() 如果 string 是标题化的(见 title())则返回 True,否则返回 False
string.isupper() 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
string.swapcase() 翻转 string 中的大小写
string.upper() 转换 string 中的小写字母为大写
string.join(seq) 以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
string.ljust(width) 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.lower() 转换 string 中所有大写字符为小写.
string.maketrans(intab, outtab]) maketrans() 方法用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
max(str) 返回字符串 str 中最大的字母。
min(str) 返回字符串 str 中最小的字母。
string.partition(str) 有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元 素 的 元 组 (string_pre_str,str,string_post_str),如果 string 中不包含str 则 string_pre_str == string.
string.replace(str1, str2, num=string.count(str1)) 把 string 中的 str1 替换成 str2,如果 num 指定,则替换不超过 num 次.
string.rfind(str, beg=0,end=len(string) ) 类似于 find()函数,不过是从右边开始查找.
string.rindex( str, beg=0,end=len(string)) 类似于 index(),不过是从右边开始.
string.rjust(width) 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
string.rpartition(str) 类似于 partition()函数,不过是从右边开始查找.
string.split(str="", num=string.count(str)) 以 str 为分隔符切片 string,如果 num有指定值,则仅分隔 num 个子字符串
string.splitlines([keepends]) 按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
string.startswith(obj, beg=0,end=len(string)) 检查字符串是否是以 obj 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查.
string.title() 返回"标题化"的 string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
string.translate(str, del="") 根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中
string.zfill(width) 返回长度为 width 的字符串,原字符串 string 右对齐,前面填充0
string.lstrip() 截掉 string 左边的/空格
string.rstrip() 删除 string 字符串末尾的空格.
string.strip([obj]) 在 string 上执行 lstrip()和 rstrip()
--********************************************************************************************************************************
--import------import re 模块---Python 正则表达式-------------re的主要功能函数 包括: compile, search, match, split, findall(finditer), sub(subn)---------------------------------
--********************************************************************************************************************************
Regular Expression 正则表达式)提供各种正则表达式的匹配操作,在文本解析、复杂字符串分析和信息提取时是一个非常有用的工具,下面我主要总结了re的常用方法
使用python的re模块,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。python 会将正则表达式转化为字节码,利用 C 语言的匹配引擎进行深度优先的匹配。
import re
print re.__doc__
可以查询re模块的功能信息,下面会结合几个例子说明。
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式(是否区分大小写,多行匹配等)
--re.match(pattern, string[, flags=0])------尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none--只在字符串的开始位置尝试匹配正则表达式,也就是只报告从位置 0 开始的匹配情况
匹配成功re.match方法返回一个匹配的对象,否则返回None。
如果字符串string的开头和正则表达式pattern匹配的话,返回一个相应的MatchObject的实例,否则返回None
--re.search(pattern, string[, flags=0])------搜索了一个静态字符串---扫描整个字符串并返回第一个成功的匹配。 匹配成功re.search方法返回一个匹配的对象,否则返回None--扫描整个字符串来查找匹配。如果想要搜索整个字符串来寻找匹配,应当用 search() 注意: 要在字符串的任意位置搜索的话,需要使用上面的search()。
扫描string,看是否有个位置可以匹配正则表达式pattern。如果找到了,就返回一个MatchObject的实例,否则返回None,注意这和找到长度为0的子串含义是不一样的。搜索过程受flags的影响。
--re.split(pattern, string[, maxsplit=0])------将字符串分片 将字符串在 RE 匹配的地方分片并生成一个列表 用匹配pattern的子串来分割string,如果pattern里使用了圆括号,那么被pattern匹配到的串也将作为返回值列表的一部分。
`RegexObject` 的 split() 方法在 RE 匹配的地方将字符串分片,将返回列表。它同字符串的 split() 方法相似但提供更多的定界符;split()只支持空白符和固定字符串。就象你预料的那样,也有一个模块级的 re.split() 函数。
可以将字符串匹配正则表达式的部分割开并返回一个列表
通过正则表达式将字符串分片。如果捕获括号在 RE 中使用,那么它们的内容也会作为结果列表的一部分返回。如果 maxsplit 非零,那么最多只能分出 maxsplit 个分片。
你可以通过设置 maxsplit 值来限制分片数。当 maxsplit 非零时,最多只能有 maxsplit 个分片,字符串的其馀部分被做为列表的最後部分返回。在下面的例子中,定界符可以是非数字字母字符的任意序列。
如果maxsplit不为0,则最多被分割为maxsplit个子串,剩余部分将整个地被返回。
>>> re.split('\W+', 'Words, words, words.') ['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1) ['Words', 'words, words.']
>>> re.split('(\W+)', '...words, words...') ['', '...', 'words', ', ', 'words', '...', ''] 如果正则有圆括号,并且可以匹配到字符串的开始位置的时候,返回值的第一项,会多出一个空字符串。匹配到字符结尾也是同样的道理
>>> re.split('x*', 'foo') ['foo'] 注意,split不会被零长度的正则所分割
>>> re.split("(?m)^$", "foo\n\nbar\n") ['foo\n\nbar\n']
--re.findall(pattern, string[, flags])------在字符串中找到正则表达式所匹配的所有子串,并组成一个列表返回 以列表的形式返回string里匹配pattern的不重叠的子串。string会被从左到右依次扫描,返回的列表也是从左到右一次匹配到的。如果pattern里含有组的话,那么会返回匹配到的组的列表;如果pattern里有多个组,那么各组会先组成一个元组,然后返回值将是一个元组的列表。
由于这个函数不会涉及到MatchObject之类的概念,所以,对新手来说,应该是最好理解也最容易使用的一个函数了。下面就此来举几个简单的
>>> re.findall('\w+', 'hello, world!') ['hello', 'world']
#这个返回的就是元组的列表
>>> re.findall('(\d+)\.(\d+)\.(\d+)\.(\d+)', 'My IP is 192.168.0.2, and your is 192.168.0.3.') [('192', '168', '0', '2'), ('192', '168', '0', '3')]
--re.finditer(pattern, string[, flags])------和findall()类似,但返回的是MatchObject的实例的迭代器。
在字符串中找到正则表达式所匹配的所有子串,并组成一个迭代器返回。同样 RegexObject 有:
>>> for m in re.finditer('\w+', 'hello, world!'):
... print m.group()
...
hello
world
--re.sub(pattern, repl, string, count=0, flags=0)------修改替换字符串中的匹配项。 找到 RE 匹配的所有子串,并将其用一个不同的字符串替换 在字符串 string 中找到匹配正则表达式 pattern 的所有子串,用另一个字符串 repl 进行替换。如果没有找到匹配 pattern 的串,则返回未被修改的 string。Repl 既可以是字符串也可以是一个函数。
替换,将string里,匹配pattern的部分,用repl替换掉,最多替换count次(剩余的匹配将不做处理),然后返回替换后的字符串。如果string里没有可以匹配pattern的串,将被原封不动地返回。repl可以是一个字符串,也可以是一个函数(也可以参考我以前的例子)。如果repl是个字符串,则其中的反斜杆会被处理过,比如 \n 会被转成换行符,反斜杆加数字会被替换成相应的组,比如 \6 表示pattern匹配到的第6个组的内容。
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
... r'static PyObject*\npy_\1(void)\n{',
... 'def myfunc():')
'static PyObject*\npy_myfunc(void)\n{'
如果repl是个函数,每次pattern被匹配到的时候,都会被调用一次,传入一个匹配到的MatchObject对象,需要返回一个字符串,在匹配到的位置,就填入返回的字符串。
>>> def dashrepl(matchobj):
... if matchobj.group(0) == '-': return ' '
... else: return '-'
>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 'pro--gram files'
>>> re.sub('x*', '-', 'abcxxd') '-a-b-c-d-' 零长度的匹配也会被替换
特殊地,在替换字符串里,如果有\g这样的写法,将匹配正则的命名组(前面介绍过的,(?P...)这样定义出来的东西)。\g这样的写法,也是数字的组,也就是说,\g<2>一般和\2是等效的,但是万一你要在\2后面紧接着写上字面意义的0,你就不能写成\20了(因为这代表第20个组),这时候必须写成\g<2>0,另外,\g<0>代表匹配到的整个子串。
>>> re.sub('-(\d+)-', '-\g<1>0\g<0>', 'a-11-b-22-c') 'a-110-11-b-220-22-c'
sub(replacement, string[, count = 0])
返回的字符串是在字符串中用 RE 最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回。
可选参数 count 是模式匹配后替换的最大次数;count 必须是非负整数。缺省值是 0 表示替换所有的匹配。
这里有个使用 sub() 方法的简单例子。它用单词 "colour" 替换颜色名。
#!python
>>> p = re.compile( '(blue|white|red)')
>>> p.sub( 'colour', 'blue socks and red shoes')
'colour socks and colour shoes'
>>> p.sub( 'colour', 'blue socks and red shoes', count=1)
'colour socks and red shoes'
subn() 方法作用一样,但返回的是包含新字符串和替换执行次数的两元组。
#!python
>>> p = re.compile( '(blue|white|red)')
>>> p.subn( 'colour', 'blue socks and red shoes') ('colour socks and colour shoes', 2)
>>> p.subn( 'colour', 'no colours at all') ('no colours at all', 0) 空匹配只有在它们没有紧挨着前一个匹配时才会被替换掉。
#!python
>>> p = re.compile('x*')
>>> p.sub('-', 'abxd') '-a-b-d-'
#!python
>>> p = re.compile('x*')
>>> p.sub('-', 'abxd') '-a-b-d-'
#!python
>>> p = re.compile(r'"W+')
>>> p.split('This is a test, short and sweet, of split().') ['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
>>> p.split('This is a test, short and sweet, of split().', 3) ['This', 'is', 'a', 'test, short and sweet, of split().']
有时,你不仅对定界符之间的文本感兴趣,也需要知道定界符是什么。如果捕获括号在 RE 中使用,那么它们的值也会当作列表的一部分返回。比较下面的调用:
#!python
>>> p = re.compile(r'"W+')
>>> p2 = re.compile(r'("W+)')
>>> p.split('This is a test.') ['This', 'is', 'a', 'test', '']
>>> p2.split('This is a test.') ['This', ' ', 'is', ' ', 'a', ' ', 'test', '.', '']
模块级函数 re.split() 将 RE 作为第一个参数,其他一样。
#!python
>>> re.split('["W]+', 'Words, words, words.') ['Words', 'words', 'words', '']
>>> re.split('(["W]+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('["W]+', 'Words, words, words.', 1) ['Words', 'words, words.']
如果替换的是一个字符串,任何在其中的反斜杠都会被处理。""n" 将会被转换成一个换行符,""r"转换成回车等等。未知的转义如 ""j" 则保持原样。逆向引用,如 ""6",被 RE 中相应的组匹配而被子串替换。这使你可以在替换後的字符串中插入原始文本的一部分。
这个例子匹配被 "{" 和 "}" 括起来的单词 "section",并将 "section" 替换成 "subsection"。
#!python
>>> p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{"1}','section{First} section{second}')
'subsection{First} subsection{second}'
还可以指定用 (?P<name>...) 语法定义的命名组。""g<name>" 将通过组名 "name" 用子串来匹配,并且 ""g<number>" 使用相应的组号。所以 ""g<2>" 等于 ""2",但能在替换字符串里含义不清,如 ""g<2>0"。(""20" 被解释成对组 20 的引用,而不是对後面跟着一个字母 "0" 的组 2 的引用。)
#!python
>>> p = re.compile('section{ (?P<name> [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{"1}','section{First}') 'subsection{First}'
>>> p.sub(r'subsection{"g<1>}','section{First}') 'subsection{First}'
>>> p.sub(r'subsection{"g<name>}','section{First}') 'subsection{First}'
替换也可以是一个甚至给你更多控制的函数。如果替换是个函数,该函数将会被模式中每一个不重复的匹配所调用。在每个调用时,函数被作为 `MatchObject` 的匹配函属,并可以使用这个信息去计算预期的字符串并返回它。
在下面的例子里,替换函数将十进制翻译成十六进制:
#!python
>>> def hexrepl( match ):
"Return the hex string for a decimal number"
value = int( match.group() )
return hex(value)
>>> p = re.compile(r'"d+')
>>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'
当使用模块级的 re.sub() 函数时,模式作为第一个参数。模式也许是一个字符串或一个 `RegexObject`;如果你需要指定正则表达式标志,你必须要么使用 `RegexObject` 做第一个参数,或用使用模式内嵌修正器,如 sub("(?i)b+", "x", "bbbb BBBB") returns 'x x'。
常见问题
正则表达式对一些应用程序来说是一个强大的工具,但在有些时候它并不直观而且有时它们不按你期望的运行。本节将指出一些最容易犯的常见错误。
使用字符串方式
有时使用 re 模块是个错误。如果你匹配一个固定的字符串或单个的字符类,并且你没有使用 re 的任何象 IGNORECASE 标志的功能,那么就没有必要使用正则表达式了。字符串有一些方法是对固定字符串进行操作的,它们通常快很多,因为都是一个个经过优化的C 小循环,用以代替大的、更具通用性的正则表达式引擎。
举个用一个固定字符串替换另一个的例子;如,你可以把 "deed" 替换成 "word"。re.sub() seems like the function to use for this, but consider the replace() method. 注意 replace() 也可以在单词里面进行替换,可以把 "swordfish" 变成 "sdeedfish",不过 RE 也是可以做到的。(为了避免替换单词的一部分,模式将写成 "bword"b,这是为了要求 "word" 两边有一个单词边界。这是个超出替换能力的工作)。
另一个常见任务是从一个字符串中删除单个字符或用另一个字符来替代它。你也许可以用象 re.sub('"n',' ',S) 这样来实现,但 translate() 能够实现这两个任务,而且比任何正则表达式操作起来更快。
总之,在使用 re 模块之前,先考虑一下你的问题是否可以用更快、更简单的字符串方法来解决。
match() vs search()
match() 函数只检查 RE 是否在字符串开始处匹配,而 search() 则是扫描整个字符串。记住这一区别是重要的。记住,match() 只报告一次成功的匹配,它将从 0 处开始;如果匹配不是从 0 开始的,match() 将不会报告它。
#!python
>>> print re.match('super', 'superstition').span() (0, 5)
>>> print re.match('super', 'insuperable') None
另一方面,search() 将扫描整个字符串,并报告它找到的第一个匹配。
#!python
>>> print re.search('super', 'superstition').span() (0, 5)
>>> print re.search('super', 'insuperable').span() (2, 7)
有时你可能倾向于使用 re.match(),只在RE的前面部分添加 .* 。请尽量不要这么做,最好采用 re.search() 代替之。正则表达式编译器会对 REs 做一些分析以便可以在查找匹配时提高处理速度。一个那样的分析机会指出匹配的第一个字符是什么;举个例子,模式 Crow 必须从 "C" 开始匹配。分析机可以让引擎快速扫描字符串以找到开始字符,并只在 "C" 被发现後才开始全部匹配。
添加 .* 会使这个优化失败,这就要扫描到字符串尾部,然後回溯以找到 RE 剩馀部分的匹配。使用 re.search() 代替。
--re.subn(pattern, repl, string[, count, flags])------与 sub() 相同,但返回新的字符串和替换次数 该函数的功能和 sub() 相同,但它还返回新的字符串以及替换的次数。同样 RegexObject 有:
跟上面的sub()函数一样,只是它返回的是一个元组 (新字符串, 匹配到的次数)
,还是用例子说话:
>>> re.subn('-(\d+)-', '-\g<1>0\g<0>', 'a-11-b-22-c')
('a-110-11-b-220-22-c', 2)
--re.escape(string) 把string中,除了字母和数字以外的字符,都加上反斜杆。
>>> print re.escape('[email protected]#$') abc123\_\@\#\$
exception re.error
如果字符串不能被成功编译成正则表达式或者正则表达式在匹配过程中出错了,都会抛出此异常。但是如果正则表达式没有匹配到任何文本,是不会抛出这个异常的。
--re.compile(pattern[, flags]) 把一个正则表达式pattern编译成正则对象,以便可以用正则对象的match和search方法。 把正则表达式语法转化成正则表达式对象
得到的正则对象的行为(也就是模式)可以用flags来指定,值可以由几个下面的值OR得到。
以下两段内容在语法上是等效的:
prog = re.compile(pattern)
result = prog.match(string)
result = re.match(pattern, string)
区别是,用了re.compile以后,正则对象会得到保留,这样在需要多次运用这个正则对象的时候,效率会有较大的提升。再用上面用过的例子来演示一下,用相同的正则匹配相同的字符串,执行100万次,就体现出compile的效率了(数据来自我那1.86G CPU的神舟本本):
>>> timeit.timeit(
... setup='''import re; reg = re.compile('<(?P<tagname>\w*)>.*</(?P=tagname)>')''',
... stmt='''reg.match('<h1>xxx</h1>')''',
... number=1000000)
1.2062149047851562
>>> timeit.timeit(
... setup='''import re''',
... stmt='''re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h1>')''',
... number=1000000)
4.4380838871002197
--正则表达式--修饰符---可选标志-----编译标志----让你可以修改正则表达式的一些运行方式。在 re 模块中标志可以使用两个名字,一个是全名如 IGNORECASE,一个是缩写,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同样的字母;例如 re.VERBOSE的缩写形式是 re.X。)多个标志可以通过按位 OR-ing 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
flags定义,编译本RE时,指定的标志位,如果未指定任何标志位,则为0。
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。
修饰符被指定为一个可选的标志。
多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
re.I re.IGNORECASE 让正则表达式忽略大小写,这样一来,[A-Z]也可以匹配小写字母了。此特性和locale无关。
字符类和字符串匹配字母时忽略大小写。举个例子,[A-Z]也可以匹配小写字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。这个小写字母并不考虑当前位置。
re.L re.LOCALE 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境 做本地化识别(locale-aware)匹配 让\w、\W、\b、\B、\s和\S依赖当前的locale。
影响 \w, \W, \b, 和 \B,这取决于当前的本地化设置。 locales 是 C 语言库中的一项功能,是用来为需要考虑不同语言的编程提供帮助的。举个例子,如果你正在处理法文文本,你想用 \w+ 来匹配文字,但 \w 只匹配字符类 [A-Za-z];它并不能匹配 "é" 或 "?"。如果你的系统配置适当且本地化设置为法语,那么内部的 C 函数将告诉程序 "é" 也应该被认为是一个字母。当在编译正则表达式时使用 LOCALE 标志会得到用这些 C 函数来处理 \w 后的编译对象;这会更慢,但也会象你希望的那样可以用 \w+ 来匹配法文文本。
re.M re.MULTILINE 多行匹配,影响 ^ 和 $的行为,指定了以后,'^'会增加匹配每行的开始(也就是换行符后的位置);'$'会增加匹配每行的结束(也就是换行符前的位置)。
(此时 ^ 和 $ 不会被解释; 它们将在 4.1 节被介绍.) 使用 "^" 只匹配字符串的开始,而 $ 则只匹配字符串的结尾和直接在换行前(如果有的话)的字符串结尾。当本标志指定后, "^" 匹配字符串的开始和字符串中每行的开始。同样的, $ 元字符匹配字符串结尾和字符串中每行的结尾(直接在每个换行之前)。
re.S re.DOTALL ' . '并且包括换行符在内的任意字符(注意: ' . '不包括换行符)
影响'.'的行为,平时'.'匹配除换行符以外的所有字符,指定了本标志以后,也可以匹配换行符。
使 . 匹配包括换行在内的所有字符 使 "." 特殊字符完全匹配任何字符,包括换行;没有这个标志, "." 匹配除了换行外的任何字符。
re.U re.UNICODE 让\w、\W、\b、\B、\d、\D、\s和\S依赖Unicode库。 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X re.VERBOSE 能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂 运用这个标志,你可以写出可读性更好的正则表达式: 除了在方括号内的和被反斜杠转义的以外的所有空白字符,都将被忽略,而且每行中,一个正常的井号后的所有字符也被忽略,这样就可以方便地在正则表达式内部写注释了。也就是说,下面两个正则表达式是等效的:
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写入 RE,这些注释会被引擎忽略;注释用 "#"号 来标识,不过该符号不能在字符串或反斜杠之后。
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
我通常更喜欢使用编译对象,甚至它只用一次,but few people will be as much of a purist about this as I am。
举个例子,这里有一个使用 re.VERBOSE 的 RE;看看读它轻松了多少?
#!python
charref = re.compile(r"""
&[[]] # Start of a numeric entity reference
(
[0-9]+[^0-9] # Decimal form
| 0[0-7]+[^0-7] # Octal form
| x[0-9a-fA-F]+[^0-9a-fA-F] # Hexadecimal form
)
""", re.VERBOSE)
没有 verbose 设置, RE 会看起来象这样:
--正则对象---由re.compile()返回。它有如下的属性和方法------这几个函数,都和模块的相应函数一致。
pos是开始搜索的位置,默认为0。
endpos是搜索的结束位置,如果endpos比pos还小的话,结果肯定是空的。也就是说只有pos 到 endpos-1 位置的字符串将会被搜索。
match(string[, pos[, endpos]]) 作用和模块的match()函数类似,区别就是后面两个参数。
search(string[, pos[, endpos]]) 作用和模块的search()函数类似,pos和endpos参数和上面的match()函数类似。
findall(string[, pos[, endpos]])
finditer(string[, pos[, endpos]])
sub(repl, string[, count=0])
subn(repl, string[, count=0])
split(string [, maxsplit = 0])
>>> pattern = re.compile("o")
>>> pattern.match("dog") # 开始位置不是o,所以不匹配
>>> pattern.match("dog", 1) # 第二个字符是o,所以匹配
<_sre.SRE_Match object at ...>
>>> pattern = re.compile("o", re.S|re.U)
>>> pattern.flags
48
--比较详细Python正则表达式操作指南(re使用)
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。Python 1.5之前版本则是通过 regex 模块提供 Emecs 风格的模式。Emacs 风格模式可读性稍差些,而且功能也不强,因此编写新代码时尽量不要再使用 regex 模块,当然偶尔你还是可能在老代码里发现其踪影。
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。使用这个小型语言,你可以为想要匹配的相应字符串集指定规则;该字符串集可能包含英文语句、e-mail地址、TeX命令或任何你想搞定的东西。然後你可以问诸如“这个字符串匹配该模式吗?”或“在这个字符串中是否有部分匹配该模式呢?”。你也可以使用 RE 以各种方式来修改或分割字符串。
正则表达式模式被编译成一系列的字节码,然後由用 C 编写的匹配引擎执行。在高级用法中,也许还要仔细留意引擎是如何执行给定 RE ,如何以特定方式编写 RE 以令生产的字节码运行速度更快。本文并不涉及优化,因为那要求你已充分掌握了匹配引擎的内部机制。
正则表达式语言相对小型和受限(功能有限),因此并非所有字符串处理都能用正则表达式完成。当然也有些任务可以用正则表达式完成,不过最终表达式会变得异常复杂。碰到这些情形时,编写 Python 代码进行处理可能反而更好;尽管 Python 代码比一个精巧的正则表达式要慢些,但它更易理解。
简单模式
我们将从最简单的正则表达式学习开始。由于正则表达式常用于字符串操作,那我们就从最常见的任务: 字符匹配 下手。
有关正则表达式底层的计算机科学上的详细解释(确定性和非确定性有限自动机),你可以查阅编写编译器相关的任何教科书。
字符匹配
大多数字母和字符一般都会和自身匹配。例如,正则表达式 test 会和字符串“test”完全匹配。(你也可以使用大小写不敏感模式,它还能让这个 RE 匹配“Test”或“TEST”;稍後会有更多解释。)
这个规则当然会有例外;有些字符比较特殊,它们和自身并不匹配,而是会表明应和一些特殊的东西匹配,或者它们会影响到 RE 其它部分的重复次数。本文很大篇幅专门讨论了各种元字符及其作用。
这里有一个元字符的完整列表;其含义会在本指南馀下部分进行讨论。
. ^ $ * + ? { [ ] \ | ( )
我们首先考察的元字符是"[" 和 "]"。它们常用来指定一个字符类别,所谓字符类别就是你想匹配的一个字符集。字符可以单个列出,也可以用“-”号分隔的两个给定字符来表示一个字符区间。例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。如果你只想匹配小写字母,那幺 RE 应写成 [a-z].
元字符在类别里并不起作用。例如,[akm$]将匹配字符"a", "k", "m", 或 "$" 中的任意一个;"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。
你可以用补集来匹配不在区间范围内的字符。其做法是把"^"作为类别的首个字符;其它地方的"^"只会简单匹配 "^"字符本身。例如,[^5] 将匹配除 "5" 之外的任意字符。
也许最重要的元字符是反斜杠"""。 做为 Python 中的字符串字母,反斜杠後面可以加不同的字符以表示不同特殊意义。它也可以用于取消所有的元字符,这样你就可以在模式中匹配它们了。举个例子,如果你需要匹配字符 "[" 或 """,你可以在它们之前用反斜杠来取消它们的特殊意义: "[ 或 ""。
一些用 """ 开始的特殊字符所表示的预定义字符集通常是很有用的,象数字集,字母集,或其它非空字符集。下列是可用的预设特殊字符:
这样特殊字符都可以包含在一个字符类中。如,["s,.]字符类将匹配任何空白字符或","或"."。
本节最後一个元字符是 . 。它匹配除了换行字符外的任何字符,在 alternate 模式(re.DOTALL)下它甚至可以匹配换行。"." 通常被用于你想匹配“任何字符”的地方。
重复
正则表达式第一件能做的事是能够匹配不定长的字符集,而这是其它能作用在字符串上的方法所不能做到的。 不过,如果那是正则表达式唯一的附加功能的话,那么它们也就不那么优秀了。它们的另一个功能就是你可以指定正则表达式的一部分的重复次数。
我们讨论的第一个重复功能的元字符是 *。* 并不匹配字母字符 "*";相反,它指定前一个字符可以被匹配零次或更多次,而不是只有一次。
举个例子,ca*t 将匹配 "ct" (0 个 "a" 字符), "cat" (1 个 "a"), "caaat" (3 个 "a" 字符)等等。RE 引擎有各种来自 C 的整数类型大小的内部限制,以防止它匹配超过2亿个 "a" 字符;你也许没有足够的内存去建造那么大的字符串,所以将不会累计到那个限制。
象 * 这样地重复是“贪婪的”;当重复一个 RE 时,匹配引擎会试着重复尽可能多的次数。如果模式的後面部分没有被匹配,匹配引擎将退回并再次尝试更小的重复。
一步步的示例可以使它更加清晰。让我们考虑表达式 a[bcd]*b。它匹配字母 "a",零个或更多个来自类 [bcd]中的字母,最後以 "b" 结尾。现在想一想该 RE 对字符串 "abcbd" 的匹配。
Step Matched Explanation
1 a a 匹配模式
2 abcbd 引擎匹配 [bcd]*,并尽其所能匹配到字符串的结尾
3 Failure 引擎尝试匹配 b,但当前位置已经是字符的最後了,所以失败
4 abcb 退回,[bcd]*尝试少匹配一个字符。
5 Failure 再次尝次b,但在当前最後一位字符是"d"。
6 abc 再次退回,[bcd]*只匹配 "bc"。
7 abcb 再次尝试 b ,这次当前位上的字符正好是 "b"
RE 的结尾部分现在可以到达了,它匹配 "abcb"。这证明了匹配引擎一开始会尽其所能进行匹配,如果没有匹配然後就逐步退回并反复尝试 RE 剩下来的部分。直到它退回尝试匹配 [bcd] 到零次为止,如果随後还是失败,那么引擎就会认为该字符串根本无法匹配 RE 。
另一个重复元字符是 +,表示匹配一或更多次。请注意 * 和 + 之间的不同;*匹配零或更多次,所以根本就可以不出现,而 + 则要求至少出现一次。用同一个例子,ca+t 就可以匹配 "cat" (1 个 "a"), "caaat" (3 个 "a"), 但不能匹配 "ct"。
还有更多的限定符。问号 ? 匹配一次或零次;你可以认为它用于标识某事物是可选的。例如: home-?brew 匹配 "homebrew" 或 "home-brew"。
最复杂的重复限定符是 {m,n},其中 m 和 n 是十进制整数。该限定符的意思是至少有 m 个重复,至多到 n 个重复。举个例子,a/{1,3}b 将匹配 "a/b","a//b" 和 "a///b"。它不能匹配 "ab" 因为没有斜杠,也不能匹配 "a////b" ,因为有四个。
你可以忽略 m 或 n;因为会为缺失的值假设一个合理的值。忽略 m 会认为下边界是 0,而忽略 n 的结果将是上边界为无穷大 -- 实际上是先前我们提到的 2 兆,但这也许同无穷大一样。
细心的读者也许注意到其他三个限定符都可以用这样方式来表示。 {0,} 等同于 *,{1,} 等同于 +,而{0,1}则与 ? 相同。如果可以的话,最好使用 *,+,或?。很简单因为它们更短也再容易懂。
使用正则表达式
现在我们已经看了一些简单的正则表达式,那么我们实际在 Python 中是如何使用它们的呢? re 模块提供了一个正则表达式引擎的接口,可以让你将 REs 编译成对象并用它们来进行匹配。
编译正则表达式
正则表达式被编译成 `RegexObject` 实例,可以为不同的操作提供方法,如模式匹配搜索或字符串替换。
#!python
>>> import re
>>> p = re.compile('ab*')
>>> print p
<re.RegexObject instance at 80b4150>
re.compile() 也接受可选的标志参数,常用来实现不同的特殊功能和语法变更。我们稍後将查看所有可用的设置,但现在只举一个
#!python
>>> p = re.compile('ab*', re.IGNORECASE)
RE 被做为一个字符串发送给 re.compile()。REs 被处理成字符串是因为正则表达式不是 Python 语言的核心部分,也没有为它创建特定的语法。(应用程序根本就不需要 REs,因此没必要包含它们去使语言说明变得臃肿不堪。)而 re 模块则只是以一个 C 扩展模块的形式来被 Python 包含,就象 socket 或 zlib 模块一样。
将 REs 作为字符串以保证 Python 语言的简洁,但这样带来的一个麻烦就是象下节标题所讲的。
反斜杠的麻烦
在早期规定中,正则表达式用反斜杠字符 (""") 来表示特殊格式或允许使用特殊字符而不调用它的特殊用法。这就与 Python 在字符串中的那些起相同作用的相同字符产生了冲突。
让我们举例说明,你想写一个 RE 以匹配字符串 ""section",可能是在一个 LATEX 文件查找。为了要在程序代码中判断,首先要写出想要匹配的字符串。接下来你需要在所有反斜杠和元字符前加反斜杠来取消其特殊意义。
字符 阶段
\section 要匹配的字符串
\\section 为 re.compile 取消反斜杠的特殊意义
"\\\\section" 为字符串取消反斜杠
简单地说,为了匹配一个反斜杠,不得不在 RE 字符串中写 '\\',因为正则表达式中必须是 "\\",而每个反斜杠按 Python 字符串字母表示的常规必须表示成 "\\"。在 REs 中反斜杠的这个重复特性会导致大量重复的反斜杠,而且所生成的字符串也很难懂。
解决的办法就是为正则表达式使用 Python 的 raw 字符串表示;在字符串前加个 "r" 反斜杠就不会被任何特殊方式处理,所以 r"\n" 就是包含"\" 和 "n" 的两个字符,而 "\n" 则是一个字符,表示一个换行。正则表达式通常在 Python 代码中都是用这种 raw 字符串表示。
常规字符串 Raw 字符串
"ab*" r"ab*"
"\\\\section" r"\\section"
"\\w+\\s+\\1" r"\w+\s+\1"
执行匹配
一旦你有了已经编译了的正则表达式的对象,你要用它做什么呢?`RegexObject` 实例有一些方法和属性。这里只显示了最重要的几个,如果要看完整的列表请查阅 Python Library Reference
方法/属性 作用
group() 返回被 RE 匹配的字符串
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置
试试这些方法不久就会清楚它们的作用了:
match() 决定 RE 是否在字符串刚开始的位置匹配
search() 扫描字符串,找到这个 RE 匹配的位置
findall() 找到 RE 匹配的所有子串,并把它们作为一个列表返回
finditer() 找到 RE 匹配的所有子串,并把它们作为一个迭代器返回
如果没有匹配到的话,match() 和 search() 将返回 None。如果成功的话,就会返回一个 `MatchObject` 实例,其中有这次匹配的信息: 它是从哪里开始和结束,它所匹配的子串等等。
你可以用采用人机对话并用 re 模块实验的方式来学习它。如果你有 Tkinter 的话,你也许可以考虑参考一下 Tools/scripts/redemo.py,一个包含在 Python 发行版里的示范程序。
首先,运行 Python 解释器,导入 re 模块并编译一个 RE:
#!python
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
<_sre.SRE_Pattern object at 80c3c28>
现在,你可以试着用 RE 的 [a-z]+ 去匹配不同的字符串。一个空字符串将根本不能匹配,因为 + 的意思是 “一个或更多的重复次数”。 在这种情况下 match() 将返回 None,因为它使解释器没有输出。你可以明确地打印出 match() 的结果来弄清这一点。
#!python
>>> p.match("")
>>> print p.match("")
None
现在,让我们试着用它来匹配一个字符串,如 "tempo"。这时,match() 将返回一个 MatchObject。因此你可以将结果保存在变量里以便后面使用。
#!python
>>> m = p.match( 'tempo')
>>> print m
<_sre.SRE_Match object at 80c4f68>
现在你可以查询 `MatchObject` 关于匹配字符串的相关信息了。MatchObject 实例也有几个方法和属性;最重要的那些如下所示:
--使用group(num) 或 groups() 匹配对象函数来获取匹配表达式
group(num=0) 匹配的整个表达式的字符串, group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
group() 可以一次输入多个组号,在这种情况下,它将返回一个包含那些组所对应值的元组。
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号
作用: 在字符串中查找匹配正则表达式模式的位置,返回 MatchObject 的实例,如果没有找到匹配的位置,则返回 None。
#!python
>>> m.group() 'tempo'
>>> m.start(), m.end() (0, 5)
>>> m.span() (0, 5)
group() 返回 RE 匹配的子串。start() 和 end() 返回匹配开始和结束时的索引。span() 则用单个元组把开始和结束时的索引一起返回。因为匹配方法检查到如果 RE 在字符串开始处开始匹配,那么 start() 将总是为零。然而, `RegexObject` 实例的 search 方法扫描下面的字符串的话,在这种情况下,匹配开始的位置就也许不是零了。
#!python
>>> print p.match('::: message') None
>>> m = p.search('::: message') ; print m
<re.MatchObject instance at 80c9650>
>>> m.group() 'message'
>>> m.span() (4, 11)
在实际程序中,最常见的作法是将 `MatchObject` 保存在一个变量里,然后检查它是否为 None,通常如下所示:
#!python
p = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'
两个 `RegexObject` 方法返回所有匹配模式的子串。findall()返回一个匹配字符串行表:
#!python
>>> p = re.compile('\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']
findall() 在它返回结果时不得不创建一个列表。在 Python 2.2中,也可以用 finditer() 方法。
#!python
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable-iterator object at 0x401833ac>
>>> for match in iterator:
... print match.span()
...
(0, 2)
(22, 24)
(29, 31)
#!python
>>> print p.match('::: message')
None
>>> m = p.search('::: message') ; print m
<re.MatchObject instance at 80c9650>
>>> m.group() 'message'
>>> m.span() (4, 11)
本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以是Unicode字符,这点不用担心,python会处理地和Ascii字符一样漂亮。
正则表达式使用反斜杆(\)来转义特殊字符,使其可以匹配字符本身,而不是指定其他特殊的含义。这可能会和python字面意义上的字符串转义相冲突,这也许有些令人费解。比如,要匹配一个反斜杆本身,你也许要用'\\\\'来做为正则表达式的字符串,因为正则表达式要是\\,而字符串里,每个反斜杆都要写成\\。
你也可以在字符串前加上 r 这个前缀来避免部分疑惑,因为 r 开头的python字符串是 raw 字符串,所以里面的所有字符都不会被转义,比如r'\n'这个字符串就是一个反斜杆加上一字母n,而'\n'我们知道这是个换行符。因此,上面的'\\\\'你也可以写成r'\\',这样,应该就好理解很多了。可以看下面这段:
>>> import re
>>> s = '\x5c' #0x5c就是反斜杆
>>> print s
\
>>> re.match('\\\\', s) #这样可以匹配
<_sre.SRE_Match object at 0xb6949e20>
>>> re.match(r'\\', s) #这样也可以
<_sre.SRE_Match object at 0x80ce2c0>
>>> re.match('\\', s) #但是这样不行
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/re.py", line 137, in match
return _compile(pattern, flags).match(string)
File "/usr/lib/python2.6/re.py", line 245, in _compile
raise error, v # invalid expression
sre_constants.error: bogus escape (end of line)
>>>
另外值得一提的是,re模块的方法,大多也就是RegexObject对象的方法,两者的区别在于执行效率。这个在最后再展开吧。
>>> re.findall('(foo.$)', 'foo1\nfoo2\n') ['foo2']
>>> re.findall('(foo.$)', 'foo1\nfoo2\n', re.MULTILINE) ['foo1', 'foo2']
>>> re.findall('($)', 'foo\n') ['', '']
*?, +?, ??
从前面的描述可以看到'*','+'和'?'都是贪婪的,但这也许并不是我们说要的,所以,可以在后面加个问号,将策略改为非贪婪,只匹配尽量少的RE。示例,体会两者的区别:
>>> re.findall('<(.*)>', '<H1>title</H1>') ['H1>title</H1']
>>> re.findall('<(.*?)>', '<H1>title</H1>') ['H1', '/H1']
--正则表达式--模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 '\\t')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
正则表达式语法
正则表达式(RE)指定一个与之匹配的字符集合;本模块所提供的函数,将可以用来检查所给的字符串是否与指定的正则表达式匹配。
正则表达式可以被连接,从而形成新的正则表达式;例如A和B都是正则表达式,那么AB也是正则表达式。一般地,如果字符串p与A匹配,q与B匹配的话,那么字符串pq也会与AB匹配,但A或者B里含有边界限定条件或者命名组操作的情况除外。也就是说,复杂的正则表达式可以用简单的连接而成。
正则表达式可以包含特殊字符和普通字符,大部分字符比如'A','a'和'0'都是普通字符,如果做为正则表达式,它们将匹配它们本身。由于正则表达式可以连接,所以连接多个普通字符而成的正则表达式last也将匹配'last'。(后面将用不带引号的表示正则表达式,带引号的表示字符串)
下面就来介绍正则表达式的特殊字符:
--更多的元字符----零宽界定符(zero-width assertions)。它们并不会使引擎在处理字符串时更快;相反,它们根本就没有对应任何字符,只是简单的成功或失败。
举个例子, "b 是一个在单词边界定位当前位置的界定符(assertions),这个位置根本就不会被 "b 改变。这意味着零宽界定符(zero-width assertions)将永远不会被重复,因为如果它们在给定位置匹配一次,那么它们很明显可以被匹配无数次。
. 点号 在普通模式,匹配任意字符,除了换行符外
如果指定了re.DOTALL标记,匹配包括换行符的任意字符
$ 美元号,匹配一个字符串的结尾或者字符串最后面的换行符,在 MULTILINE 模式下,也匹配任意一行的行尾。也就是说,普通模式下,foo.$去搜索'foo1\nfoo2\n'只会找到'foo2′,但是在 MULTILINE 模式,还能找到 ‘foo1′,而且就用一个 $ 去搜索'foo\n'的话,会找到两个空的匹配: 一个是最后的换行符,一个是字符串的结尾,演示:
$ 匹配字符串的末尾
$ 匹配行尾,行尾被定义为要么是字符串尾,要么是一个换行字符后面的任何位置。 匹配一个 "$",使用 "$ 或将其包含在字符类中,如[$]。
下面的例子只匹配 "class" 整个单词;而当它被包含在其他单词中时不匹配。
匹配一个 "$",使用 \$ 或将其包含在字符类中,如[$]。
^ 尖尖号 未设置MULTILINE 标志,只是匹配字符串的开始
在 MULTILINE 模式下,也可以直接匹配字符串中的每个换行(匹配行首)也将匹配任意一个新行的开始
如果你只希望匹配在行首单词 "From",那幺 RE 将用 ^From。
'^hello'匹配'helloworld'而不匹配'aaaahellobbb'
* 星号 0 个或多个字符 指定将前面的RE重复0次或者任意多次,而且总是试图尽量多次地匹配。 (贪婪匹配)
+ 加号 1 个或多个字符(贪婪匹配) 指定将前面的RE重复1次或者任意多次,而且总是试图尽量多次地匹配。
? 问号 0 个或多个字符(贪婪匹配) 指定将前面的RE重复0次或者1次,如果有的话,也尽量匹配1次。
| 或 A|B,或运算
| 可选项,或者 "or" 操作符。如果 A 和 B 是正则表达式,A|B 将匹配任何匹配了 "A" 或 "B" 的字符串。| 的优先级非常低,是为了当你有多字符串要选择时能适当地运行。Crow|Servo 将匹配"Crow" 或 "Servo", 而不是 "Cro", 一个 "w" 或 一个 "S", 和 "ervo"。 为了匹配字母 "|",可以用 "|,或将其包含在字符类中,如[|]。
<*>匹配<title>chinaunix</title>
*?,+?,?? 以上三个取第一个匹配结果(非贪婪匹配) <*>匹配<title>
{m,n} 对于前一个字符重复m到n次,{m}亦可 a{6}匹配6个a、a{2,4}匹配2到4个a
{m,n}? 对于前一个字符重复m到n次,并取尽可能少 ‘aaaaaa'中a{2,4}只会匹配2个
"\\" 特殊字符转义或者特殊序列
[] 表示一个字符集 [0-9]、[a-z]、[A-Z]、[^0]
(...) 匹配括号中任意表达式
(?#...) 注释,可忽略
(?=...) Matches if ... matches next, but doesn't consume the string. '(?=test)' 在hellotest中匹配hello
(?!...) Matches if ... doesn't match next. '(?!=test)' 若hello后面不为test,匹配hello
(?<=...) Matches if preceded by ... (must be fixed length). '(?<=hello)test' 在hellotest中匹配test
(?<!...) Matches if not preceded by ... (must be fixed length). '(?<!hello)test' 在hellotest中不匹配test
{m} m是一个数字,指定将前面的RE重复m次。
{m,n} m和n都是数字,指定将前面的RE重复m到n次,例如a{3,5}匹配3到5个连续的a。注意,如果省略m,将匹配0到n个前面的RE;如果省略n,将匹配n到无穷多个前面的RE;当然中间的逗号是不能省略的,不然就变成前面那种形式了。
{m,n}? 前面说的{m,n},也是贪婪的,a{3,5}如果有5个以上连续a的话,会匹配5个,这个也可以通过加问号改变。a{3,5}?如果可能的话,将只匹配3个a。
'\' 反斜杆,转义'*','?'等特殊字符,或者指定一个特殊序列(下面会详述)
由于之前所述的原因,强烈建议用raw字符串来表述正则。
[] 方括号,用于指定一个字符的集合。可以单独列出字符,也可以用'-'连接起止字符以表示一个范围。特殊字符在中括号里将失效,比如[akm$]就表示字符'a','k','m',或'$',在这里$也变身为普通字符了。[a-z]匹配任意一个小写字母,[a-zA-Z0-9]匹配任意一个字母或数字。如果你要匹配']'或'-'本身,你需要加反斜杆转义,或者是将其置于中括号的最前面,比如[]]可以匹配']'
你还可以对一个字符集合取反,以匹配任意不在这个字符集合里的字符,取反操作用一个'^'放在集合的最前面表示,放在其他地方的'^'将不会起特殊作用。例如[^5]将匹配任意不是'5'的字符;[^^]将匹配任意不是'^'的字符。
注意: 在中括号里,+、*、(、)这类字符将会失去特殊含义,仅作为普通字符。反向引用也不能在中括号内使用。
'|' 管道符号,A和B是任意的RE,那么A|B就是匹配A或者B的一个新的RE。任意个数的RE都可以像这样用管道符号间隔连接起来。这种形式可以被用于组中(后面将详述)。对于目标字符串,被'|'分割的RE将自左至右一一被测试,一旦有一个测试成功,后面的将不再被测试,即使后面的RE可能可以匹配更长的串,换句话说,'|'操作符是非贪婪的。要匹配字面意义上的'|',可以用反斜杆转义: \|,或是包含在反括号内: [|]。
(...) 匹配圆括号里的RE匹配的内容,并指定组的开始和结束位置。组里面的内容可以被提取,也可以采用\number这样的特殊序列,被用于后续的匹配。要匹配字面意义上的'('和')',可以用反斜杆转义: \(、\),或是包含在反括号内: [(]、[)]。
(?...) 这是一个表达式的扩展符号。'?'后的第一个字母决定了整个表达式的语法和含义,除了(?P...)以外,表达式不会产生一个新的组。下面介绍几个目前已被支持的扩展:
(?iLmsux) 'i'、'L'、'm'、's'、'u'、'x'里的一个或多个字母。表达式不匹配任何字符,但是指定相应的标志: re.I(忽略大小写)、re.L(依赖locale)、re.M(多行模式)、re.S(.匹配所有字符)、re.U(依赖Unicode)、re.X(详细模式)。关于各个模式的区别,下面会有专门的一节来介绍的。使用这个语法可以代替在re.compile()的时候或者调用的时候指定flag参数。
例如,上面举过的例子,可以改写成这样(和指定了re.MULTILINE是一样的效果):
>>> re.findall('(?m)(foo.$)', 'foo1\nfoo2\n') ['foo1', 'foo2']
另外,还要注意(?x)标志如果有的话,要放在最前面。
(?:...) 匹配内部的RE所匹配的内容,但是不建立组。
(?P<name>...) 和普通的圆括号类似,但是子串匹配到的内容将可以用命名的name参数来提取。组的name必须是有效的python标识符,而且在本表达式内不重名。命名了的组和普通组一样,也用数字来提取,也就是说名字只是个额外的属性。
演示一下:
>>> m=re.match('(?P<var>[a-zA-Z_]\w*)', 'abc=123')
>>> m.group('var') 'abc'
>>> m.group(1) 'abc' (?P=name)
匹配之前以name命名的组里的内容。
演示一下:
>>> re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h2>') #这个不匹配
>>> re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h1>') #这个匹配
<_sre.SRE_Match object at 0xb69588e0>
(?#...) 注释,圆括号里的内容会被忽略。
(?=...) 如果 ... 匹配接下来的字符,才算匹配,但是并不会消耗任何被匹配的字符。例如 Isaac (?=Asimov) 只会匹配后面跟着 'Asimov' 的 'Isaac ',这个叫做“前瞻断言”。
(?!...) 和上面的相反,只匹配接下来的字符串不匹配 ... 的串,这叫做“反前瞻断言”。
(?<=...) 只有当当前位置之前的字符串匹配 ... ,整个匹配才有效,这叫“后顾断言”。字符串'abcdef'可以匹配正则(?<=abc)def,因为会后向查找3个字符,看是否为abc。所以内置的子RE,需要是固定长度的,比如可以是abc、a|b,但不能是a*、a{3,4}。注意这种RE永远不会匹配到字符串的开头。举个例子,找到连字符('-')后的单词:
>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0) 'egg'
(?<!...)
同理,这个叫做“反后顾断言”,子RE需要固定长度的,含义是前面的字符串不匹配 ... 整个才算匹配。
(?(id/name)yes-pattern|no-pattern)
如有由id或者name指定的组存在的话,将会匹配yes-pattern,否则将会匹配no-pattern,通常情况下no-pattern也可以省略。例如: (<)?(\[email protected]\w+(?:\.\w+)+)(?(1)>)可以匹配 '<[email protected]>' 和 '[email protected]',但是不会匹配 '<[email protected]'。
下面列出以'\'开头的特殊序列。如果某个字符没有在下面列出,那么RE的结果会只匹配那个字母本身,比如,\$只匹配字面意义上的'$'。
#\u2076\和u2084分别是上标的6和下标的4,属于unicode的DIGIT
>>> unistr = u'\u2076\u2084abc'
>>> print unistr ??abc
>>> print re.findall('\d+', unistr, re.U)[0]
[...] 用来表示一组字符,单独列出: [amk] 匹配 'a','m'或'k'
[^...] 不在[]中的字符: [^abc] 匹配除了a,b,c之外的字符。
re* 匹配0个或多个的表达式。
re+ 匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n}
re{ n,} 精确匹配n个前面表达式。
re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b 匹配a或b
(re) G匹配括号内的表达式,也表示一个组
(?imx) 正则表达式包含三种可选标志: i, m, 或 x 。只影响括号中的区域。
(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re) 类似 (...), 但是不表示一个组
(?imx: re) 在括号中使用i, m, 或 x 可选标志
(?-imx: re) 在括号中不使用i, m, 或 x 可选标志
(?#...) 注释.
(?= re) 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re) 匹配的独立模式,省去回溯。
--字符匹配--字符类
python 匹配 "python".
[Pp]ython 匹配 "Python" 或 "python"
rub[ye] 匹配 "ruby" 或 "rube"
[aeiou] 匹配中括号内的任意一个字母
[0-9] 匹配任何数字,类似于 [0123456789]
[a-z] 匹配任何小写字母
[A-Z] 匹配任何大写字母
[a-zA-Z0-9] 匹配任何字母及数字
[^aeiou] 除了aeiou字母以外的所有字符
[^0-9] 匹配除了数字外的字符
--特殊字符类
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
\d 匹配一个数字字符。等价于 [0-9] 匹配任意数字 匹配任何十进制数 未指定UNICODE标志时,匹配数字,等效于: [0-9]。指定了UNICODE标志时,还会匹配其他Unicode库里描述为字符串的符号。便于理解,举个例子(好不容易找的例子啊,呵呵):
\D 匹配任何非数字字符;相当于[^0-9] 匹配任意非数字 匹配一个非数字字符。等价于 [^0-9] 和\d相反,不多说了。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\s 匹配任意空白字符,等价于 [\t\n\r\f] 当未指定UNICODE和LOCALE这两个标志位时,匹配任何空白字符,等效于[ \t\n\r\f\v]。如果指定了LOCALE,则还要加LOCALE相关的空白字符;如果指定了UNICODE,还要加上UNICODE空白字符,如较常见的空宽度连接空格(\uFEFF)、零宽度非连接空格(\u200B)等。
\S 匹配任意非空白字符:[^\t\n\r\r\v] 匹配任何非空白字符;它相当于类 [^ "t"n"r"f"v] 和\s相反,也不多说。
\S 匹配任意非空字符 等价于 [^ \f\n\r\t\v]。
\w 匹配任意数字和字母及下划线(包括下划线的任何单词字符。等价于'[A-Za-z0-9_]') 当未指定UNICODE和LOCALE这两个标志位时,等效于[a-zA-Z0-9_]。当指定了LOCALE时,为[0-9_]加上当前LOCAL指定的字母。当指定了UNICODE时,为[0-9_]加上UNICODE库里的所有字母。
\W 匹配任意非数字和字母:[^a-zA-Z0-9]
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]。
\W 匹配非字母数字及下划线(任何非单词字符。等价于 '[^A-Za-z0-9_]') 和\w相反,不多说。
\A 只在字符串开始进行匹配 只匹配字符串的开始 匹配字符串开始
\Z 只在字符串结尾进行匹配 只匹配字符串的结尾 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\b 匹配位于开始或结尾的空字符串
\b 匹配单词边界(包括开始和结束),这里的“单词”,是指连续的字母、数字和下划线组成的字符串。注意,\b的定义是\w和\W的交界,所以精确的定义有赖于UNICODE和LOCALE这两个标志位。
\B 匹配不位于开始或结尾的空字符串 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 和\b相反,\B匹配非单词边界。
也依赖于UNICODE和LOCALE这两个标志位。
\A 只匹配字符串首。当不在 MULTILINE 模式,\A 和 ^ 实际上是一样的。然而,在 MULTILINE 模式里它们是不同的;\A 只是匹配字符串首,而 ^ 还可以匹配在换行符之后字符串的任何位置。
\Z Matches only at the end of the string. 只匹配字符串尾。
\b 单词边界。这是个零宽界定符(zero-width assertions)只用以匹配单词的词首和词尾。单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标示的。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1...\9 匹配第n个分组的内容。
\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。
\number 匹配number所指的组相同的字符串。组的序号从1开始。例如: (.+) \1可以匹配'the the'和'55 55',但不匹配'the end'。这种序列在一个正则表达式里最多可以有99个,如果number以0开头,或是有3位以上的数字,就会被当做八进制表示的字符了。同时,这个也不能用于方括号内。
"A 只匹配字符串首。当不在 MULTILINE 模式,"A 和 ^ 实际上是一样的。然而,在 MULTILINE 模式里它们是不同的;"A 只是匹配字符串首,而 ^ 还可以匹配在换行符之後字符串的任何位置。
"Z Matches only at the end of the string. 只匹配字符串尾。
"b 单词边界。这是个零宽界定符(zero-width assertions)只用以匹配单词的词首和词尾。单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标示的。
#!python
charref = re.compile("&#([0-9]+[^0-9]"
"|0[0-7]+[^0-7]"
"|x[0-9a-fA-F]+[^0-9a-fA-F])")
在上面的例子里,Python 的字符串自动连接可以用来将 RE 分成更小的部分,但它比用 re.VERBOSE 标志时更难懂。
--使用组来检索被匹配的文本部分。
我通常更喜欢使用编译对象,甚至它只用一次,but few people will be as much of a purist about this as I am。
--零基础写python爬虫之神器正则表达式
内容太多,很多图片 http://www.jb51.net/article/57150.htm
正则表达式是一个特殊的字符序列,它能帮助方便的检查一个字符串是否与某种模式匹配。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
--模块级函数
你不一定要产生一个 `RegexObject` 对象然后再调用它的方法;re 模块也提供了顶级函数调用如 match()、search()、sub() 等等。这些函数使用 RE 字符串作为第一个参数,而后面的参数则与相应 `RegexObject` 的方法参数相同,返回则要么是 None 要么就是一个 `MatchObject` 的实例。
#!python
>>> print re.match(r'From\s+', 'Fromage amk')
None
>>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998')
<re.MatchObject instance at 80c5978>
Under the hood, 这些函数简单地产生一个 RegexOject 并在其上调用相应的方法。它们也在缓存里保存编译后的对象,因此在将来调用用到相同 RE 时就会更快。
你将使用这些模块级函数,还是先得到一个 `RegexObject` 再调用它的方法呢?如何选择依赖于怎样用 RE 更有效率以及你个人编码风格。如果一个 RE 在代码中只做用一次的话,那么模块级函数也许更方便。如果程序包含很多的正则表达式,或在多处复用同一个的话,那么将全部定义放在一起,在一段代码中提前 编译所有的 REs 更有用。从标准库中看一个例子,这是从 xmllib.py 文件中提取出来的:
#!python
ref = re.compile( )
entityref = re.compile( )
charref = re.compile( )
starttagopen = re.compile( )
--详解Python里使用正则表达式的ASCII模式
ASCII(American Standard Code for Information Interchange),是一种单字节的编码。这篇文章主要介绍了Python里使用正则表达式的ASCII模式,需要的朋友可以参考下
计算机世界里一开始只有英文,而单字节可以表示256个不同的字符,可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半(\x80以下),这也是MBCS得以实现的基础。
目前,基本上都使用python3来开发了,但是有时为了兼容旧的python2的代码,在正则表达式里主要是字符串的表示方式不同了,在python3里是使用Unicode来表示字符串和正则表达式,而在python2里是使用ASCII来表示的,所以在python3里怎么样设置才兼容旧的方式呢?其实可以通过ASCII的标志来解决,如下面的
#python 3.6
#蔡军生
#http://blog.csdn.net/caimouse/article/details/51749579
#
import re
text = u'Fran?ais z?oty ?sterreich'
pattern = r'\w+'
ascii_pattern = re.compile(pattern, re.ASCII)
unicode_pattern = re.compile(pattern)
print('Text :', text)
print('Pattern :', pattern)
print('ASCII :', list(ascii_pattern.findall(text)))
print('Unicode :', list(unicode_pattern.findall(text)))
结果输出如下:
Text : Fran?ais z?oty ?sterreich
Pattern : \w+
ASCII : ['Fran', 'ais', 'z', 'oty', 'sterreich']
Unicode : ['Fran?ais', 'z?oty', '?sterreich']
总结
以上所述是小编给大家介绍的详解Python里使用正则表达式的ASCII模式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
--Python 匹配任意字符(包括换行符)的正则表达式写法
想使用正则表达式来获取一段文本中的任意字符,写出如下匹配规则:
(.*) 结果运行之后才发现,无法获得换行之后的文本。于是查了一下手册,才发现正则表达式中,“.”(点符号)匹配的是除了换行符“\n”以外的所有字符。
以下为正确的正则表达式匹配规则:
([\s\S]*)
同时,也可以用 “([\d\D]*)”、“([\w\W]*)” 来表示。 Web技术之家_www.waweb.cn
在文本文件里, 这个表达式可以匹配所有的英文
/[ -~]/
--Python正则表达式匹配ip地址实例
本文实例讲述了正则表达式匹配ip地址实例。代码结构非常简单易懂。分享给大家供大家参考。
主要实现代码如下:
import re
reip = re.compile(r'(?<![\.\d])(?:\d{1,3}\.){3}\d{1,3}(?![\.\d])')
for ip in reip.findall(line):
print "ip>>>", ip
--python中如何正确使用正则表达式的详细模式(Verbose mode expression)
许多程序设计语言都支持利用正则表达式进行字符串操作,python自然也不例外,下面这篇文章主要给大家介绍了关于在python中如何正确使用正则表达式的详细模式(Verbose mode expression)的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
简单介绍
正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同;但不用担心,不被支持的语法通常是不常用的部分。如果已经在其他语言里使用过正则表达式,只需要简单看一看就可以上手了。
下图展示了使用正则表达式进行匹配的流程:
正则表达式的大致匹配过程是: 依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。
引言
当大家写的正则表达式比较长,比较复杂时,发现经常会写错,或者很难维护,遇到这种情况怎么办呢?这个不用急,聪明的设计人员早已经想到这种情况了,提供了一种叫做详细模式(Verbose mode expression)。当你使用这种模式时,可以给正则表达式添加注释,这样在维护时就不会像看天书了,同时也可以添加额外的空格,进行对齐排版。
紧凑模式的
import re
address = re.compile('[\w\d.+-][email protected]([\w\d.]+\.)+(com|org|edu)')
candidates = [
]
for candidate in candidates:
match = address.search(candidate)
print('{:<30} {}'.format(
candidate, 'Matches' if match else 'No match')
)
详细模式的修改之后:
#python 3.6
#蔡军生
#http://blog.csdn.net/caimouse/article/details/51749579
#
import re
address = re.compile(
'''''
[\w\d.+-]+ # username
@
([\w\d.]+\.)+ # domain name prefix
(com|org|edu) # TODO: support more top-level domains
''',
re.VERBOSE)
candidates = [
]
for candidate in candidates:
match = address.search(candidate)
print('{:<30} {}'.format(
candidate, 'Matches' if match else 'No match'),
)
结果输出如下:
[email protected] Matches
[email protected] Matches
[email protected] Matches
[email protected] No match
参数解释: X VERBOSE
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之後;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写入 RE,这些注释会被引擎忽略;注释用 "#"号 来标识,不过该符号不能在字符串或反斜杠之後。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
--python中如何使用正则表达式的非贪婪模式示例
作者: caimouse 字体: [增加 减小] 类型: 转载 时间: 2017-10-09 我要评论
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,下面这篇文章主要给大家介绍了关于python中如何使用正则表达式的非贪婪模式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
前言
本文主要给大家介绍了关于python使用正则表达式的非贪婪模式的相关内容,分享出来供大家参考学习,下面话不多说了,来一起详细的介绍吧。
在正则表达式里,什么是正则表达式的贪婪与非贪婪匹配
如: String str="abcaxc";
Patter p="ab*c";
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到: abcaxc(ab*c)。
非贪婪匹配: 就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到: abc(ab*c)。
解决这个问题,可以采用:
正则引擎默认是贪婪的,当出现"*"时,它会尽量去匹配尽可能长的字符串。
一个用于修正以上问题的可能方案是用"*"的惰性代替贪婪性。你可以在"*"后面紧跟一个问号"?"来达到这一点
这告诉正则引擎,尽可能少的重复上一个字符。
如下面的
#python 3. 6
#蔡军生
#http://blog.csdn.net/caimouse/article/details/51749579
#
from re_test_patterns import test_patterns
test_patterns(
'abbaabbba',
[('ab*?', 'a followed by zero or more b'),
('ab+?', 'a followed by one or more b'),
('ab??', 'a followed by zero or one b'),
('ab{3}?', 'a followed by three b'),
('ab{2,3}?', 'a followed by two to three b')],
)
输出结果如下:
'ab*?' (a followed by zero or more b)
'abbaabbba'
'a'
...'a'
....'a'
........'a'
'ab+?' (a followed by one or more b)
'abbaabbba'
'ab'
....'ab'
'ab??' (a followed by zero or one b)
'abbaabbba'
'a'
...'a'
....'a'
........'a'
'ab{3}?' (a followed by three b)
'abbaabbba'
....'abbb'
'ab{2,3}?' (a followed by two to three b)
'abbaabbba'
'abb'
....'abb'
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
--python如何使用正则表达式的前向、后向搜索及前向搜索否定模式
这篇文章主要给大家介绍了关于python如何使用正则表达式的前向、后向搜索及前向搜索否定模式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
前言
在许多的情况下,很多要匹配内容是一起出现,或者一起不出现的。比如《》,< >,这样的括号,不存在使用半个的情况。因此,在正则表达式里也有一致性的判断,要么两个尖括号一起出现,要么一个也不要出现。怎么样来实现这种判断呢?针对这种情况得引入新的正则表达式的语法: (?=pattern),这个语法它会向前搜索或者向后搜索相关内容,如果不会出现就不能匹配。不过,这个匹配不会消耗任何输入的字符,它只是查看一下。
例子如下:
#python 3.6
#蔡军生
#http://blog.csdn.net/caimouse/article/details/51749579
#
import re
address = re.compile(
'''''
# A name is made up of letters, and may include "."
# for title abbreviations and middle initials.
((?P<name>
([\w.,]+\s+)*[\w.,]+
)
\s+
) # name is no longer optional
# LOOKAHEAD
# Email addresses are wrapped in angle brackets, but only
# if both are present or neither is.
(?= (<.*>$) # remainder wrapped in angle brackets
|
([^<].*[^>]$) # remainder *not* wrapped in angle brackets
)
<? # optional opening angle bracket
# The address itself: [email protected]
(?P<email>
[\w\d.+-]+ # username
@
([\w\d.]+\.)+ # domain name prefix
(com|org|edu) # limit the allowed top-level domains
)
>? # optional closing angle bracket
''',
re.VERBOSE)
candidates = [
u'First Last <[email protected]>',
u'No Brackets [email protected]',
u'Open Bracket <[email protected]',
u'Close Bracket [email protected]>',
]
for candidate in candidates:
print('Candidate:', candidate)
match = address.search(candidate)
if match:
print(' Name :', match.groupdict()['name'])
print(' Email:', match.groupdict()['email'])
else:
print(' No match')
结果输出如下:
Candidate: First Last <[email protected]>
Name : First Last
Email: [email protected]
Candidate: No Brackets [email protected]
Name : No Brackets
Email: [email protected]
Candidate: Open Bracket <[email protected]
No match
Candidate: Close Bracket [email protected]>
No match
python里使用正则表达式的前向搜索否定模式
上面学习前向搜索或后向搜索模式(?=pattern),这个模式里看到有等于号=,它是表示一定相等,其实前向搜索模式里,还有不相等的判断。比如你需要识别EMAIL地址: [email protected],这个EMAIL地址大多数是不需要回复的,所以我们要把这个EMAIL地址识别出来,并且丢掉它。怎么办呢?这时你就需要使用前向搜索否定模式,它的语法是这样: (?!pattern),这里的感叹号就是表示非,不需要的意思。比如遇到这样的字符串: [email protected],它会判断[email protected]是否相同,如果相同,就丢掉这个模式识别,不再匹配。
例子如下:
#python 3.6
#蔡军生
#http://blog.csdn.net/caimouse/article/details/51749579
#
import re
address = re.compile(
'''''
^
# An address: [email protected]
# Ignore noreply addresses
[\w\d.+-]+ # username
@
([\w\d.]+\.)+ # domain name prefix
(com|org|edu) # limit the allowed top-level domains
$
''',
re.VERBOSE)
candidates = [
]
for candidate in candidates:
print('Candidate:', candidate)
match = address.search(candidate)
if match:
print(' Match:', candidate[match.start():match.end()])
else:
print(' No match')
结果输出如下:
Candidate: [email protected]
Match: [email protected]
Candidate: [email protected]
No match
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
实例 1
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配
以上实例运行输出结果为:
(0, 3)
None
实例 2
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print "matchObj.group() : ", matchObj.group()
print "matchObj.group(1) : ", matchObj.group(1)
print "matchObj.group(2) : ", matchObj.group(2)
else:
print "No match!!"
以上实例执行结果如下:
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
实例 1
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
以上实例运行输出结果为:
(0, 3)
(11, 14)
实例 2
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print "searchObj.group() : ", searchObj.group()
print "searchObj.group(1) : ", searchObj.group(1)
print "searchObj.group(2) : ", searchObj.group(2)
else:
print "Nothing found!!"
以上实例执行结果如下:
searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
匹配之搜索
python提供了两种基于正则表达式的操作: 匹配(match)从字符串的开始检查字符串是否个正则匹配。而搜索(search)检查字符串任意位置是否有匹配的子串(perl默认就是如此)。
注意,即使search的正则以'^'开头,match和search也还是有许多不同的。
>>> re.match("c", "abcdef") # 不匹配
>>> re.search("c", "abcdef") # 匹配
<_sre.SRE_Match object at ...>
模块的属性和方法
groups RE所含有的组的个数。
groupindex 一个字典,定义了命名组的名字和序号之间的关系。
这个正则有3个组,如果匹配到,第一个叫区号,最后一个叫分机号,中间的那个未命名
>>> pattern = re.compile("(?P<quhao>\d+)-(\d+)-(?P<fenjihao>\d+)")
>>> pattern.groups
3
>>> pattern.groupindex
{'fenjihao': 3, 'quhao': 1}
pattern
建立本RE的原始字符串,相当于源代码了,呵呵。
还是上面这个正则,可以看到,会原样返回:
>>> print pattern.pattern
(?P<quhao>\d+)-(\d+)-(?P<fenjihao>\d+)
Match对象
re.MatchObject被用于布尔判断的时候,始终返回True,所以你用 if 语句来判断某个 match() 是否成功是安全的。
它有以下方法和属性:
expand(template)
用template做为模板,将MatchObject展开,就像sub()里的行为一样,看
>>> m = re.match('a=(\d+)', 'a=100')
>>> m.expand('above a is \g<1>') 'above a is 100'
>>> m.expand(r'above a is \1') 'above a is 100'
--group([group1, ...]) 返回一个或多个子组。如果参数为一个,就返回一个子串;如果参数有多个,就返回多个子串注册的元组。如果不传任何参数,效果和传入一个0一样,将返回整个匹配。如果某个groupN未匹配到,相应位置会返回None。如果某个groupN是负数或者大于group的总数,则会抛出IndexError异常。
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0) # 整个匹配 'Isaac Newton'
>>> m.group(1) # 第一个子串 'Isaac'
>>> m.group(2) # 第二个子串 'Newton'
>>> m.group(1, 2) # 多个子串组成的元组 ('Isaac', 'Newton')
如果有其中有用(?P...)这种语法命名过的子串的话,相应的groupN也可以是名字字符串。例如:
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name') 'Malcolm'
>>> m.group('last_name') 'Reynolds'
如果某个组被匹配到多次,那么只有最后一次的数据,可以被提取到:
>>> m = re.match(r"(..)+", "a1b2c3") # 匹配到3次
>>> m.group(1) # 返回的是最后一次 'c3'
--groups([default]) 返回一个由所有匹配到的子串组成的元组。default参数,用于给那些没有匹配到的组做默认值,它的默认值是None
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups() ('24', '1632')
default的作用:
>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups() # 第二个默认是None
('24', None)
>>> m.groups('0') # 现在默认是0了
('24', '0')
--groupdict([default]) 返回一个包含所有命名组的名字和子串的字典,default参数,用于给那些没有匹配到的组做默认值,它的默认值是None,例如:
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict() {'first_name': 'Malcolm', 'last_name': 'Reynolds'}
start([group])
end([group]) 返回的是: 被组group匹配到的子串在原字符串中的位置。如果不指定group或group指定为0,则代表整个匹配。如果group未匹配到,则返回 -1。
对于指定的m和g,m.group(g)和m.string[m.start(g):m.end(g)]等效。
注意: 如果group匹配到空字符串,m.start(group)和m.end(group)将相等。
例如:
>>> m = re.search('b(c?)', 'cba')
>>> m.start(0) 1
>>> m.end(0) 2
>>> m.start(1) 2
>>> m.end(1) 2
下面是一个把email地址里的“remove_this”去掉的
>>> email = "[email protected]_thisger.net"
>>> m = re.search("remove_this", email)
>>> email[:m.start()] + email[m.end():]
--span([group]) 返回一个元组: (m.start(group), m.end(group))
pos 就是传给RE对象的search()或match()方法的参数pos,代表RE开始搜索字符串的位置。
endpos 就是传给RE对象的search()或match()方法的参数endpos,代表RE搜索字符串的结束位置。
lastindex 最后一次匹配到的组的数字序号,如果没有匹配到,将得到None。 例如: (a)b、((a)(b))和((ab))正则去匹配'ab'的话,得到的lastindex为1。而用(a)(b)去匹配'ab'的话,得到的lastindex为2。
lastgroup 最后一次匹配到的组的名字,如果没有匹配到或者最后的组没有名字,将得到None。
re 得到本Match对象的正则表达式对象,也就是执行search()或match()的对象。
string 传给search()或match()的字符串。
后面的例子就略了吧,文中已经加了很多我自己的例子了,需要更多例子的话,参照英文原文吧(https://docs.python.org/2/library/re.html)。
正则表达式是一个复杂的主题。本文能否有助于你理解呢?那些部分是否不清晰,或在这儿没有找到你所遇到的问题?如果是那样的话,请将建议发给作者以便改进
#!python
>>> p = re.compile(r'\W+')
>>> p.split('This is a test, short and sweet, of split().') ['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
>>> p.split('This is a test, short and sweet, of split().', 3) ['This', 'is', 'a', 'test, short and sweet, of split().']
有时,你不仅对定界符之间的文本感兴趣,也需要知道定界符是什么。如果捕获括号在 RE 中使用,那么它们的值也会当作列表的一部分返回。比较下面的调用:
#!python
>>> p = re.compile(r'\W+')
>>> p2 = re.compile(r'(\W+)')
>>> p.split('This... is a test.') ['This', 'is', 'a', 'test', '']
>>> p2.split('This... is a test.') ['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']
模块级函数 re.split() 将 RE 作为第一个参数,其他一样。
#!python
>>> re.split('[\W]+', 'Words, words, words.') ['Words', 'words', 'words', '']
>>> re.split('([\W]+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('[\W]+', 'Words, words, words.', 1) ['Words', 'words, words.']
实例
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
phone = "2004-959-559 # 这是一个国外电话号码"
num = re.sub(r'#.*$', "", phone) # 删除字符串中的 Python注释
print "电话号码是: ", num
num = re.sub(r'\D', "", phone) # 删除非数字(-)的字符串
print "电话号码是 : ", num
以上实例执行结果如下:
电话号码是: 2004-959-559
电话号码是 : 2004959559
repl 参数是一个函数
以下实例中将字符串中的匹配的数字乘于 2:
实例
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
# 将匹配的数字乘于 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
执行输出结果为:
A46G8HFD1134
实例
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print "match --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print "search --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
以上实例运行结果如下:
No match!!
search --> matchObj.group() : dogs
当用这个特殊序列时你应该记住这里有两个微妙之处。第一个是 Python 字符串和正则表达式之间最糟的冲突。在 Python 字符串里,"\b" 是反斜杠字符,ASCII值是8。如果你没有使用 raw 字符串时,那么 Python 将会把 "\b" 转换成一个回退符,你的 RE 将无法象你希望的那样匹配它了。下面的例子看起来和我们前面的 RE 一样,但在 RE 字符串前少了一个 "r" 。
#!python
>>> p = re.compile('\bclass\b')
>>> print p.search('no class at all') None
>>> print p.search('\b' + 'class' + '\b')
<re.MatchObject instance at 80c3ee0>
第二个在字符类中,这个限定符(assertion)不起作用,\b 表示回退符,以便与 Python 字符串兼容。
\B 另一个零宽界定符(zero-width assertions),它正好同 \b 相反,只在当前位置不在单词边界时匹配。
分组
你经常需要得到比 RE 是否匹配还要多的信息。正则表达式常常用来分析字符串,编写一个 RE 匹配感兴趣的部分并将其分成几个小组。举个例子,一个 RFC-822 的头部用 ":" 隔成一个头部名和一个值,这就可以通过编写一个正则表达式匹配整个头部,用一组匹配头部名,另一组匹配头部值的方式来处理。
组是通过 "(" 和 ")" 元字符来标识的。 "(" 和 ")" 有很多在数学表达式中相同的意思;它们一起把在它们里面的表达式组成一组。举个例子,你可以用重复限制符,象 *, +, ?, 和 {m,n},来重复组里的内容,比如说(ab)* 将匹配零或更多个重复的 "ab"。
#!python
>>> p = re.compile('(ab)*')
>>> print p.match('ababababab').span() (0, 10)
组用 "(" 和 ")" 来指定,并且得到它们匹配文本的开始和结尾索引;这就可以通过一个参数用 group()、start()、end() 和 span() 来进行检索。组是从 0 开始计数的。组 0 总是存在;它就是整个 RE,所以 `MatchObject` 的方法都把组 0 作为它们缺省的参数。稍後我们将看到怎样表达不能得到它们所匹配文本的 span。
#!python
>>> p = re.compile('(a)b')
>>> m = p.match('ab')
>>> m.group() 'ab'
>>> m.group(0) 'ab'
小组是从左向右计数的,从1开始。组可以被嵌套。计数的数值可以能过从左到右计算打开的括号数来确定。
#!python
>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0) 'abcd'
>>> m.group(1) 'abc'
>>> m.group(2) 'b'
group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
#!python
>>> m.group(2,1,2) ('b', 'abc', 'b')
The groups() 方法返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
#!python
>>> m.groups() ('abc', 'b')
模式中的逆向引用允许你指定先前捕获组的内容,该组也必须在字符串当前位置被找到。举个例子,如果组 1 的内容能够在当前位置找到的话,"1 就成功否则失败。记住 Python 字符串也是用反斜杠加数据来允许字符串中包含任意字符的,所以当在 RE 中使用逆向引用时确保使用 raw 字符串。
例如,下面的 RE 在一个字符串中找到成双的词。
#!python
>>> p = re.compile(r'("b"w+)"s+"1')
>>> p.search('Paris in the the spring').group()
'the the'
象这样只是搜索一个字符串的逆向引用并不常见 -- 用这种方式重复数据的文本格式并不多见 -- 但你不久就可以发现它们用在字符串替换上非常有用。
--无捕获组和命名组
精心设计的 REs 也许会用很多组,既可以捕获感兴趣的子串,又可以分组和结构化 RE 本身。在复杂的 REs 里,追踪组号变得困难。有两个功能可以对这个问题有所帮助。它们也都使用正则表达式扩展的通用语法,因此我们来看看第一个。
Perl 5 对标准正则表达式增加了几个附加功能,Python 的 re 模块也支持其中的大部分。选择一个新的单按键元字符或一个以 "\" 开始的特殊序列来表示新的功能,而又不会使 Perl 正则表达式与标准正则表达式产生混乱是有难度的。如果你选择 "&" 做为新的元字符,举个例子,老的表达式认为 "&" 是一个正常的字符,而不会在使用 \& 或 [&] 时也不会转义。
Perl 开发人员的解决方法是使用 (?...) 来做为扩展语法。"?" 在括号后面会直接导致一个语法错误,因为 "?" 没有任何字符可以重复,因此它不会产生任何兼容问题。紧随 "?" 之后的字符指出扩展的用途,因此 (?=foo)
Python 新增了一个扩展语法到 Perl 扩展语法中。如果在问号后的第一个字符是 "P",你就可以知道它是针对 Python 的扩展。目前有两个这样的扩展: (?P<name>...) 定义一个命名组,(?P=name) 则是对命名组的逆向引用。如果 Perl 5 的未来版本使用不同的语法增加了相同的功能,那么 re 模块也将改变以支持新的语法,这是为了兼容性的目的而保持的 Python 专用语法。
现在我们看一下普通的扩展语法,我们回过头来简化在复杂 REs 中使用组运行的特性。因为组是从左到右编号的,而且一个复杂的表达式也许会使用许多组,它可以使跟踪当前组号变得困难,而修改如此复杂的 RE 是十分麻烦的。在开始时插入一个新组,你可以改变它之后的每个组号。
首先,有时你想用一个组去收集正则表达式的一部分,但又对组的内容不感兴趣。你可以用一个无捕获组: (?:...) 来实现这项功能,这样你可以在括号中发送任何其他正则表达式。
#!python
>>> m = re.match("([abc])+", "abc")
>>> m.groups()
('c',)
>>> m = re.match("(?:[abc])+", "abc")
>>> m.groups()
()
除了捕获匹配组的内容之外,无捕获组与捕获组表现完全一样;你可以在其中放置任何字符,可以用重复元字符如 "*" 来重复它,可以在其他组(无捕获组与捕获组)中嵌套它。(?:...) 对于修改已有组尤其有用,因为你可以不用改变所有其他组号的情况下添加一个新组。捕获组和无捕获组在搜索效率方面也没什么不同,没有哪一个比另一个更快。
其次,更重要和强大的是命名组;与用数字指定组不同的是,它可以用名字来指定。
命令组的语法是 Python 专用扩展之一: (?P<name>...)。名字很明显是组的名字。除了该组有个名字之外,命名组也同捕获组是相同的。`MatchObject` 的方法处理捕获组时接受的要么是表示组号的整数,要么是包含组名的字符串。命名组也可以是数字,所以你可以通过两种方式来得到一个组的信息:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print "matchObj.group() : ", matchObj.group()
print "matchObj.group(1) : ", matchObj.group(1)
print "matchObj.group(2) : ", matchObj.group(2)
else:
print "No match!!"
正则表达式:
r'(.*) are (.*?) .*'
解析:
首先,这是一个字符串,前面的一个 r 表示字符串为非转义的原始字符串,让编译器忽略反斜杠,也就是忽略转义字符。但是这个字符串里没有反斜杠,所以这个 r 可有可无。
(.*) 第一个匹配分组,.* 代表匹配除换行符之外的所有字符。
(.*?) 第二个匹配分组,.*? 后面多个问号,代表非贪婪模式,也就是说只匹配符合条件的最少字符
后面的一个 .* 没有括号包围,所以不是分组,匹配效果和第一个一样,但是不计入匹配结果中。
matchObj.group() 等同于 matchObj.group(0),表示匹配到的完整文本字符
matchObj.group(1) 得到第一组匹配结果,也就是(.*)匹配到的
matchObj.group(2) 得到第二组匹配结果,也就是(.*?)匹配到的
因为只有匹配结果中只有两组,所以如果填 3 时会报错。
--前向界定符--包括--前向肯定界定符 + 后向肯定界定符
另一个零宽界定符(zero-width assertion)是前向界定符。
(?=...) 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩馀部分还要尝试界定符的右边。
(?!...) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
通过示范在哪前向可以成功有助于具体实现。考虑一个简单的模式用于匹配一个文件名,并将其通过 "." 分成基本名和扩展名两部分。如在 "news.rc" 中,"news" 是基本名,"rc" 是文件的扩展名。
匹配模式非常简单:
.*[.].*$ 注意 "." 需要特殊对待,因为它是一个元字符;我把它放在一个字符类中。另外注意後面的 $; 添加这个是为了确保字符串所有的剩馀部分必须被包含在扩展名中。这个正则表达式匹配
"foo.bar"、"autoexec.bat"、 "sendmail.cf" 和 "printers.conf"。
现在,考虑把问题变得复杂点;如果你想匹配的扩展名不是 "bat" 的文件名?一些不正确的尝试:
.*[.][^b].*$ 上面的第一次去除 "bat" 的尝试是要求扩展名的第一个字符不是 "b"。这是错误的,因为该模式也不能匹配 "foo.bar"。
.*[.]([^b]..|.[^a].|..[^t])$ 当你试着修补第一个解决方法而要求匹配下列情况之一时表达式更乱了: 扩展名的第一个字符不是 "b"; 第二个字符不是 "a";或第三个字符不是 "t"。这样可以接受 "foo.bar" 而拒绝 "autoexec.bat",但这要求只能是三个字符的扩展名而不接受两个字符的扩展名如 "sendmail.cf"。我们将在努力修补它时再次把该模式变得复杂。
.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$ 在第三次尝试中,第二和第三个字母都变成可选,为的是允许匹配比三个字符更短的扩展名,如 "sendmail.cf"。
该模式现在变得非常复杂,这使它很难读懂。更糟的是,如果问题变化了,你想扩展名不是 "bat" 和 "exe",该模式甚至会变得更复杂和混乱。
前向否定把所有这些裁剪成:
.*[.](?!bat$).*$
前向的意思: 如果表达式 bat 在这里没有匹配,尝试模式的其馀部分;如果 bat$ 匹配,整个模式将失败。後面的 $ 被要求是为了确保象 "sample.batch" 这样扩展名以 "bat" 开头的会被允许。
将另一个文件扩展名排除在外现在也容易;简单地将其做为可选项放在界定符中。下面的这个模式将以 "bat" 或 "exe" 结尾的文件名排除在外。
.*[.](?!bat$|exe$).*$
--贪婪 vs 不贪婪
当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。当你试着匹配一对对称的定界符,如 HTML 标志中的尖括号时这个事实经常困扰你。匹配单个 HTML 标志的模式不能正常工作,因为 .* 的本质是“贪婪”的
#!python
>>> s = '<html><head><title>Title</title>'
>>> len(s)
32
>>> print re.match('<.*>', s).span()
(0, 32)
>>> print re.match('<.*>', s).group()
<html><head><title>Title</title>
RE 匹配 在 "<html>" 中的 "<",.* 消耗掉子符串的剩馀部分。在 RE 中保持更多的左,虽然 > 不能匹配在字符串结尾,因此正则表达式必须一个字符一个字符地回溯,直到它找到 > 的匹配。最终的匹配从 "<html" 中的 "<" 到 "</title>" 中的 ">",这并不是你所想要的结果。
在这种情况下,解决方案是使用不贪婪的限定符 *?、+?、?? 或 {m,n}?,尽可能匹配小的文本。在上面的例子里, ">" 在第一个 "<" 之後被立即尝试,当它失败时,引擎一次增加一个字符,并在每步重试 ">"。这个处理将得到正确的结果:
#!python
>>> print re.match('<.*?>', s).group()
<html>
注意用正则表达式分析 HTML 或 XML 是痛苦的。变化混乱的模式将处理常见情况,但 HTML 和 XML 则是明显会打破正则表达式的特殊情况;当你编写一个正则表达式去处理所有可能的情况时,模式将变得非常复杂。象这样的任务用 HTML 或 XML 解析器。
不用 re.VERBOSE
现在你可能注意到正则表达式的表示是十分紧凑,但它们非常不好读。中度复杂的 REs 可以变成反斜杠、圆括号和元字符的长长集合,以致于使它们很难读懂。
在这些 REs 中,当编译正则表达式时指定 re.VERBOSE 标志是有帮助的,因为它允许你可以编辑正则表达式的格式使之更清楚。
re.VERBOSE 标志有这么几个作用。在正则表达式中不在字符类中的空白符被忽略。这就意味着象 dog | cat 这样的表达式和可读性差的 dog|cat 相同,但 [a b] 将匹配字符 "a"、"b" 或 空格。另外,你也可以把注释放到 RE 中;注释是从 "#" 到下一行。当使用三引号字符串时,可以使 REs 格式更加干净:
#!python
pat = re.compile(r"""
\s* # Skip leading whitespace
(?P<header>[^:]+) # Header name
\s* : # Whitespace, and a colon
(?P<value>.*?) # The header's value -- *? used to
# lose the following trailing whitespace
\s*$ # Trailing whitespace to end-of-line
""", re.VERBOSE)
这个要难读得多:
#!python
pat = re.compile(r"\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s*$")
反馈
正则表达式是一个复杂的主题。本文能否有助于你理解呢?那些部分是否不清晰,或在这儿没有找到你所遇到的问题?如果是那样的话,请将建议发给作者以便改进。
描述正则表达式最全面的书非Jeffrey Friedl 写的《精通正则表达式》莫属,该书由O'Reilly 出版。可惜该书只专注于 Perl 和 Java 风格的正则表达式,不含任何 Python 材料,所以不足以用作Python编程时的参考。(第一版包含有 Python 现已过时的 regex 模块,自然用处不大)。
#!python
ref = re.compile( ... )
entityref = re.compile( ... )
charref = re.compile( ... )
starttagopen = re.compile( ... )
#!python
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word') 'Lots'
>>> m.group(1) 'Lots'
命名组是便于使用的,因为它可以让你使用容易记住的名字来代替不得不记住的数字。这里有一个来自 imaplib 模块的 RE
#!python
InternalDate = re.compile(r'INTERNALDATE "'
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
r'(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"')
很明显,得到 m.group('zonem') 要比记住得到组 9 要容易得多。
因为逆向引用的语法,象 (...)\1 这样的表达式所表示的是组号,这时用组名代替组号自然会有差别。还有一个 Python 扩展: (?P=name) ,它可以使叫 name 的组内容再次在当前位置发现。正则表达式为了找到重复的单词,(\b\w+)\s+\1 也可以被写成 (?P<word>\b\w+)\s+(?P=word):
#!python
>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
>>> p.search('Paris in the the spring').group()
'the the'
------python---正则表达式------示例------
#!python
>>> print re.search('^From', 'From Here to Eternity')
<re.MatchObject instance at 80c1520>
>>> print re.search('^From', 'Reciting From Memory') None
#!python
>>> print re.search('}$', '{block}')
<re.MatchObject instance at 80adfa8>
>>> print re.search('}$', '{block} ')
None
>>> print re.search('}$', '{block}"n')
<re.MatchObject instance at 80adfa8>
#!python
>>> p = re.compile(r'"bclass"b')
>>> print p.search('no class at all')
<re.MatchObject instance at 80c8f28>
>>> print p.search('the declassified algorithm')
None
>>> print p.search('one subclass is')
None
例: 最基本的用法,通过re.RegexObject对象调用
#!/usr/bin/env python
import re
r1 = re.compile(r'world')
if r1.match('helloworld'):
print 'match succeeds'
else:
print 'match fails'
if r1.search('helloworld'):
print 'search succeeds'
else:
print 'search fails'
说明一下: r是raw(原始)的意思。因为在表示字符串中有一些转义符,如表示回车'\n'。如果要表示\表需要写为'\\'。但如果我就是需要表示一个'\'+'n',不用r方式要写为:'\\n'。但使用r方式则为r'\n'这样清晰多了。
例: 设置flag
#r2 = re.compile(r'n$', re.S)
#r2 = re.compile('\n$', re.S)
r2 = re.compile('World$', re.I)
if r2.search('helloworld\n'):
print 'search succeeds'
else:
print 'search fails'
例: 直接调用
if re.search(r'abc','helloaaabcdworldn'):
print 'search succeeds'
else:
print 'search fails'
例: 简单分析ip
#!/usr/bin/env python
import re
r1 = re.compile('W+')
print r1.split('192.168.1.1')
print re.split('(W+)', '192.168.1.1')
print re.split('(W+)', '192.168.1.1', 1)
结果如下:
['192', '168', '1', '1']
['192', '.', '168', '.', '1', '.', '1']
['192', '.', '168.1.1']
例: 查找[]包括的内容(贪婪和非贪婪查找)
#!/usr/bin/env python
import re
r1 = re.compile('([.*])')
print re.findall(r1, "hello[hi]heldfsdsf[iwonder]lo")
r1 = re.compile('([.*?])')
print re.findall(r1, "hello[hi]heldfsdsf[iwonder]lo")
print re.findall('[0-9]{2}',"fdskfj1323jfkdj")
print re.findall('([0-9][a-z])',"fdskfj1323jfkdj")
print re.findall('(?=www)',"afdsfwwwfkdjfsdfsdwww")
print re.findall('(?<=www)',"afdsfwwwfkdjfsdfsdwww")
例:
#!/usr/bin/env python
import re
p = re.compile('(one|two|three)')
print p.sub('num', 'one word two words three words apple', 2)
首先,运行 Python 解释器,导入 re 模块并编译一个 RE:
#!python
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
<_sre.SRE_Pattern object at 80c3c28>
现在,你可以试着用 RE 的 [a-z]+ 去匹配不同的字符串。一个空字符串将根本不能匹配,因为 + 的意思是 “一个或更多的重复次数”。 在这种情况下 match() 将返回 None,因为它使解释器没有输出。你可以明确地打印出 match() 的结果来弄清这一点。
#!python
>>> p.match("")
>>> print p.match("")
None
现在,让我们试着用它来匹配一个字符串,如 "tempo"。这时,match() 将返回一个 MatchObject。因此你可以将结果保存在变量里以便后面使用。
#!python
>>> m = p.match( 'tempo')
>>> print m
<_sre.SRE_Match object at 80c4f68>
现在你可以查询 `MatchObject` 关于匹配字符串的相关信息了。MatchObject 实例也有几个方法和属性
以上是关于正则表达式--import--re--string的主要内容,如果未能解决你的问题,请参考以下文章