1. 核心笔记:查找与匹配的比较
当我们完全讨论与字符串中模式有关的正则表达式时,我们会用术语"matching"(匹配),指的是术语pattern-matching(模式匹配)。在python专门术语中,有两种主要方法完成模式匹配:搜索(searching)和匹配(matching)。搜索,即在字符串任意部分中查找匹配的模式;而匹配是指,判断一个字符串能否从起始处全部或部分的匹配某个模式。搜索通过search()函数或方法来实现,而匹配是以调用match()函数或方法来实现的。
2. 正则表达式使用的特殊符号和字符
记号 | 说明 | 举例 |
literra1 | 匹配字符串的值 | foo |
re1 | re2 | 匹配正则表达式re1或re2 | foo|bar |
.(点号) | 匹配任何字符(换行符除外) | b.b |
^ | 匹配字符串的开始 | ^Dear |
$ | 匹配字符串的结尾 | /bin/*sh$ |
* | 匹配前面出现的正则表达式零次 或 多次 | [A-Za-z0-9]* |
+ | 匹配前面出现的正则表达式一次 或 多次 | [a-z]+\.com |
? | 匹配前面出现的正则表达式零次 或 一次 | goo? |
{N} | 匹配前面出现的正则表达式N次 | [0-9]{3} |
{M,N} | 匹配重复出现M次 到 N次的正则表达式 | [0-9]{5,9} |
[...] | 匹配字符数组里出现的任意一个字符 | [aeiou] |
[..x-y..] | 匹配从字符x到y中的任意一个字符 | [0-9],[A-Za-z] |
[^...] | 不匹配此字符集中出现的任何一个字符 | [^aeiou],[^A-za-z0-9] |
(...) | 匹配封闭括号中正则表达式(re),保存为子组 | [0-9]{3} |
\d | 匹配任何数字,和[0-9]一样(\D是\d的反义:任何非数字符) | data\d+.txt |
\w | 匹配任何数字字母字符,和[A-Za-z0-9]相同(\W是其反义) | [A-Za-z]\w+ |
\s | 匹配任何空白符,和[\n\t\r\v\f]相同,(\S是其反义) | of\sthe |
\b | 匹配单词边界(\B是其反义) | \bThe\b |
\nn | 匹配已保存的子组 | price: \16 |
\c | 逐一匹配特殊字符c(即取消它的特殊含义,按字面匹配) | \. , \\, \* |
\A(\Z) | 匹配字符串的起始(结束) | \ADear |
3.
(1) 用管道符号( | )匹配多个正则表达式模式
管道符号( | ), 选择被管道符号分隔的多个不同的正则表达式中的一个。例如,下面的一些使用或操作的模式,和它们所匹配的字符串:
正则表达式模式 | 匹配的字符串 |
at | home | at , home |
bat | bet | bit | bat , bet , bit |
(2) 匹配任意一个单个的字符( . )
点字符或句号(.)符号匹配除换行符(NEWLINE)外的任意一个单个字符(Python 的正则表达式有一个编译标识 [S or DOTALL],该标识能 去掉 这一限制,使 ( . ) 在匹配时包括换行符(NEWLINEs)。)(这里括号缺一半) 无论是字母、数字、不包括“\n”的空白符、可打印的字符、还是非打印字符,或是一个符号,“点”,( . )都可以匹配他们。
正表达式模式 | 匹配的字符串 |
f.o | 在"f"和"o"中间的任何字符,如fao, f9o, f#o 等 |
.. | 任意两个字符 |
.end | 匹配在字符串end 前面的任意一个字符 |
4. Python原始字符串(raw strings)的用法:
原始字符串的产生正是由于有正则表达式的存在。原因是ASCII字符和正则表达式特殊字符间所产生的冲突。比如,特殊字符"\b"在ASCII字符中代表退格键,但同时"\b"也是正则表达式的特殊符号,代表"匹配一个单词边界"。为了让RE编译器把两个字符"\b"当成你想要表达的字符串,而不是一个退格键,你需要用另一个反斜线对它进行转义,即可以这样写"\\b"。
但是这样做会把问题复杂化,特别是当你的正则表达式字符串里有很多特殊字符时,就更容易令人困惑了。我们可以使用原始字符串,它可以用来简化正则表达式的复杂程序。事实上,很多Python程序员在定义正则表达式时都只使用原始字符串。
下面的例子用来说明退格键"\b"和正则表达式"\b"(包含或不包含原始字符串)之间的区别:
>>> m=re.match("\bblow","blow") #表达是退格,没有匹配
>>> if m is not None:m.group()
...
>>> m=re.match("\\bblow","blow") #转义后就可以匹配
>>> if m is not None:m.group()
...
'blow'
>>> m=re.match(r"\bblow","blow") #用原始字符也可以匹配
>>> if m is not None:m.group()
...
'blow'
>>>
5. 用findall找到每个出现的匹配部分
findall用于非重叠地查找某字符串中一个正则表达式模式出现的情况。findall()与search()相似之处在于二者都执行字符串搜索,但是与search和match不同之处是findall()总返回一个列表。如果findall()没有找到匹配的部分,会返回空列表;如果成功找到匹配部分,则会返回所有匹配部分的列表(按从左到右出现的顺序排列)
>>> re.findall('car','car')
['car']
>>> re.findall('car','scary')
['car']
>>> re.findall('car','carry the barcardi to the car')
['car', 'car', 'car']
包含字组的搜索会返回更复杂的一个列表,这样做是有意义的,因为子组是允许你从单个正则表达式抽取特定模式的一种机制,比如,匹配一个完整电话号码中的一部分(例如区号),或完整电子邮件地址的一部分(例如登录名)
正则表达式仅有一个子组时,findall()返回子组匹配的字符串组成列表;如果表达式有多个子组,返回的结果是一个元组的列表,元组中的每个元素都是一个子组的匹配内容,像这样的元组(每一个成功的匹配对应一个元组)构成了返回列表中的元素。
import re,urllib
htmlSource = urllib.urlopen("http://www.cnblogs.com/").read(20000)
linksList=re.findall('<a.*?href=\"(.*?)\".*?>(.*?)</a>',htmlSource)
#print linksList
for link in linksList:
print link[0]
6. python正则表达式的调试方法:
import re
numbers=["123 555 6789","1-(123)-555-6789","123-456-6789","(123).555.6789"]
for number in numbers:
pattern=re.match(r"\d{3} \d{3} \d{4}",number,re.DEBUG) #加上re.DEBUG就是开启的调试模式
if pattern:
print pattern
print pattern.group()
下面是输出的结果:
beyond@beyond ~/code/code-python $ python debug.py
max_repeat 3 3
in
category category_digit
literal 32
max_repeat 3 3
in
category category_digit
literal 32
max_repeat 4 4
in
category category_digit
<_sre.SRE_Match object at 0x7f1647b30440>
123 555 6789