python圣斗士(十七):令人欲罢不能的正则

什么是正则

字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。

正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。

所以我们判断一个字符串是否是合法的Email的方法是:

创建一个匹配Email的正则表达式;

用该正则表达式去匹配用户的输入来判断是否合法。

因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。

在正则表达式中,如果直接给出字符,就是精确匹配。用\d可以匹配一个数字,\w可以匹配一个字母或数字,所以:

'00\d'可以匹配'007',但无法匹配'00A';

'\d\d\d'可以匹配'010';

'\w\w\d'可以匹配'py3';

.可以匹配任意字符,所以:

'py.'可以匹配'pyc'、'pyo'、'py!'等等。

要匹配变长的字符,在正则表达式中,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符:

来看一个复杂的例子:\d{3}\s+\d{3,8}。

我们来从左到右解读一下:

\d{3}表示匹配3个数字,例如'010';

\s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' ',' '等;

\d{3,8}表示3-8个数字,例如'1234567'。

综合起来,上面的正则表达式可以匹配以任意个空格隔开的带区号的电话号码。

如果要匹配’010-12345’这样的号码呢?由于’-‘是特殊字符,在正则表达式中,要用’\’转义,所以,上面的正则是\d{3}-\d{3,8}。

但是,仍然无法匹配’010 - 12345’,因为带有空格。所以我们需要更复杂的匹配方式。

正则基础语法:

在正则表达式中用约定的字符串和符号作为匹配的类型和规则,这些符号就叫做元字符,下列是常见的一些正则匹配元字符:
. 匹配单个任意字符,默认不匹配换行符,除非在匹配条件末尾加上re.S选项。
* 匹配任意个任意字符
^ 匹配以某个字符开头的
?匹配单个或0个任意字符
+ 匹配单个或多个字符
[] 匹配括号中的单个字符
\ 转义符
\W 非单词字符
\w 单词字符[0-9a-zA-Z]
\D 非数字
\d纯数字
\s空格
\S匹配非空白字符)
\b:\bthe 匹配任何以the开始的字符串;\bthe\b 匹配the本身
\B:边界匹配 \Bthe 包含the但不以the为开始的字符串
参考地址:http://icybamboo.iteye.com/blog/585291

python的正则

python中关于正则的模块是re

  • 常用方法:
import re
re.findall(r'abc$','abcd')
//['abc']
re.findall
//返回匹配到的所有子串并返回列表,r表示后面所跟的为原字符串。
re.match()
//从开始位置开始匹配,一旦出现不符合正则表达式的情况则匹配失败。
re.search()
//匹配整个字符串,如果找到一个匹配则返回一个对象。
re.sub()
//替换
re.sub(r'a','A','abcabaab')
//'AbcAbAAb'

为什么要加r:r是raw(原始)的意思。因为在表示字符串中有一些转义符,如表示回车’\n’。如果要表示\表需要写为’\\’。但如果我就是需要表示一个’\’+’n’,不用r方式要写为:’\\n’。但使用r方式则为r’\n’这样清晰多了。所以一般情况下我们都会加上r。

  • 生成正则对象使用:

p=re.compile(r’abc’) 编译生成一个正则对象
p=re.compile(r’G’,re.I)

p.findall(‘aaabcacac’) 调用方法
//[‘abc’]

  • 正则标记
  • 在上面的代码中,我们注意到第二行里面在正则匹配式后面还跟着一个re.I,这个附加条件就成为正则标记,这里的意思是忽略大小写。如我们所见,正则标记就是为了更好地灵活匹配而诞生的,常见的正则标记如下:
    re.S 使得.匹配包括换行符在内的任何字符
    re.I 忽略大小写
    re.M:多行匹配,影响^和$
    re.X:启用详细的正则表达式
    re.L:支持当前的语言(区域)设置
    re.A:使得转义符号如\w,\b,\s,\d只能匹配ASCII字符

  • 正则分组
    除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)。比如:

^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

m = re.match(r’^(\d{3})-(\d{3,8})$’, ‘010-12345’)
m
//<_sre.SRE_Match object at 0x1026fb3e8>
m.group(0)
‘010-12345’
m.group(1)
//’010’
m.group(2)
//’12345’

如果正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来。

注意到group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串。

提取子串非常有用。来看一个更凶残的例子:

t = ‘19:05:30’
m = re.match(r’^(0[0-9]|1[0-9]|2[0-3]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$’, t)
m.groups()
(‘19’, ‘05’, ‘30’)

这个正则表达式可以直接识别合法的时间。但是有些时候,用正则表达式也无法做到完全验证,比如识别日期:

‘^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$’

对于’2-30’,’4-31’这样的非法日期,用正则还是识别不了,或者说写出来非常困难,这时就需要程序配合识别了。

  • 贪婪匹配

最后需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后面的0:

re.match(r’^(\d+)(0*)$’, ‘102300’).groups()
(‘102300’, ”)

由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。

必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:

re.match(r’^(\d+?)(0*)$’, ‘102300’).groups()
(‘1023’, ‘00’)

范例:
匹配IP地址:
re.search(r’(([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).){3}([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])’,’192.168.1.256’)

你可能感兴趣的:(python学习)