python基础之 正则表达式,re模块

1.正则表达式html

正则表达式:是字符串的规则,只是检测字符串是否符合条件的规则而已
    1.检测某一段字符串是否符合规则
    2.将符合规则的匹配出来
re模块:是用来操做正则表达式的

2.正则表达式组成正则表达式

字符组[] 一个字符组描述的是一个位置上的字符规则,可是不能从大到小来规定范围,字符组内全部的范围都是ascii来排序的,字符组更灵活一点
  [0-9] 匹配一个数字范围
  [a-z] 匹配一个小写字母
  [A-Z] 匹配一个大写字母
  [A-Za-z0-9] 匹配英文字母和大小写 左边必须是ascii最小的

  注意:遇到在字符组当中的'-'是有特殊意义的,若是想取消'-'的特殊意义,要转义一下
      例如:[1-2] 是匹配不是1就是2的数据,可是我想匹配1,-,2那?须要转义一下[1\-2]
            
元字符:匹配的一个字符的内容
  \d: 使用\d表示匹配任意从0-9的数字,使用字符组能匹配到一个固定的范围,可是\d表示的时从0-9太固定
   \w:匹配全部的数字字母下划线,标识符
   -t:匹配tab制表符
   \n:匹配换行符
   \s:匹配全部的空格换行制表符  
   \b:表示一个单词的边界,要匹配以XX结尾的单词
    反义词:
    \W:除了数字字母下划线的全部
    \D:除了数字以外的全部
    \S:除了空白以外的全部
    .:匹配换行符以外的全部字符

 非字符组[^123] 除了123的都匹配 ‘^’必须和[]组合才叫非字符组
 开始符'^' 结束符'$' 
  一个字符串只有一个开始和一个结束,^永远在一个规则的最前面,$永远在一个字符串的最末尾
  ^hello$ -->匹配一个hello,规定了这个字符串的长度,在字符串检测的时候一般加上^和$符号
  [^123] :匹配的是不以123开头的
 | 或的意思,竖杠的左边或右边是一个规则,永远把相对长的规则放在左边
 分组:()--> www\.(baidu|oldboy)\.com

量词:表示的是匹配的次数,在量词的范围内尽量的多的匹配,叫贪婪匹配 
  {n} 表示出现n次
   {n,} 表示出至少出现n次
   {n,m}表示存出现n-m次
   ?:匹配额0次或1次
   +:匹配1次或屡次
   *:匹配0次或屡次
  ?和+的范围等于*的范围

   匹配电话号码:^1[3-9]\d{9}$:
匹配整数:^[1-9]\d*|0&
匹配小数:\d+\.\d+
匹配整数或者小数:\d+(\.\d+)? -->里面的()是分组的意思,?表示要不()里面的一块儿出现,不要就都不出现 \d+\.?\d*
匹配15位身份证号码:^[1-9]\d{14}$
匹配18位身份证号码:^[1-9]\d{16}[\dx]$
 #转义字符:在字符串外部加上一个r来不转义
贪婪匹配:尽量的多匹配 a.*x 回溯算法
惰性匹配:尽量的少匹配 .*? ,两个量词同时出现时表示非贪婪 a.*?x 从a开始匹配,遇到一个x就中止
      就是量词后面加上?就是惰性匹配,匹配到第一个就中止
 

re模块算法

import re
s='kobe123jordan46' re.findall(pattern,string,flags=0)
  ret = re.findall('\d+',s)
  print()
  查看全部,返回一个列表
  注意:在正则条件不同的状况下返回的内容不同 '\d+'是贪婪的匹配全部数字组成一个字符串
re.search(pattern,string,flags=0)   ret =re.search('\d+',s)
  print(ret)
  print(ret.group())
  返回一个结果对象或结果集
  经过group()取值只取到第一个,若是没有符合条件的group就会报错,通常用if判断一下是否为空


re.match(pattern,string,flags=0)
  
ret = re.match('\s+',s)
  print(ret)
  返回一个结果对象或结果集
  使用match的话,至关于在正则表达式前面加上^,在程序里面匹配的是'^\s',是找以字符串开头的,没有的话就返回None
  使用search彻底能够代替match,只要在search的表达式前面加上^就能够
  re.search('^\s+','kobe123') == re.match('\s+','kobe123')

re.sub(pattern,repl,string,count=0)
  ret = re.sub('\d+','sb',s,count=1)
  print(ret)
  count不写的话默认替换全部,返回一个字符串
  
re.subn(pattern,repl,string,count=0)
  ret = re.sun('\d+','sb',s)
  print(ret)
  默认返回一个元组,而且返回被替换了多少次
re.split(pattern,string,maxsplit=1)
  ret = re.split('\d+',s,maxsplit=1)
  print(ret)
  默认返回一个列表,不加maxsplit就所有分割

re.compile(pattern)
  par = re.compile('\d+')
  ret = par.findall(s)
  print(ret)
  对于一个常常重复使用的正则表达式,咱们能够先进行一次编译,以后只要在使用这个表达式就直接拿出来使用
  就行了,这样作节省时间和及其资源,减小解析时间个转成机器码的时间
  re.compile()是一个优化函数,提高执行效率减小没必要要的时间和性能的开销

re.finditer(pattern,string)
  par = re.compile('\d+')
  ret = par.finditer('kob123kobe123kobe123kobe123'*200)
  for item in ret:
    print(item.group())
  返回的是一个生成器结果集,经过group方法取出每个数据
  看到iter应该能想到是生成器原理,经过循环每次使生成器返回一个数据,这样和使用生成器读取大文件同样,节省内存
  可以提早编译一个正则表达式,当同一个正则表达式被屡次使用时,能够直接使用节省时间


分组

  s= """
    <h1>哇哈哈哈<h1>
    <h2>哈哈哈哈<h2>
    <title>科比</title>
   """ide

  findall()和分组:分组在findall当中会默认的优先被显示出来
    ret = re.findall('>\w+<',r'<title>科比<\title>')
    print(ret[0].strip('<>'))
    分组在findall当中会默认的优先被显示出来,若是不想优先显示出来就在分组中添加(?:正则规则)表示取消这个正则的优先显示
 
    ret = re.findall('>\w+<',r'<title>科比<\title>')
    print(ret[0].strip('<>'))函数

    ret = re.findall('>(\w+)<',r'<title>科比<\title>')
    print(ret) # findall永远优先显示分组中的内容性能

    ret = re.findall('www\.(?:baidu|nba)\.com',r'www.baidu.com')
    print(ret)优化

    ret = re.findall('\d+(?:\.\d+)?',r'1.23+2.34')
    print(ret)编码

  split()和分组:会保留被切掉的在分组中内容
    ret = re.split('\d(\d)','alex84wusir73')
    print(ret)spa

  search()和分组:不受到分组的影响

    ret = re.search(r'<(\w+)>(\w+)<\\(\w+)>',r'<title>科比<\title>')
    print(ret.group(0)) # 不受到分组的影响
    print(ret.group(1))
    print(ret.group(2))code

分组命名

  #分组命名就是把一个要匹配的东西取一个名字,在之后调用返回的时候回方便,直接使用名字就OK了
  #若是有取值的有两个相同的名字的话能够复制为(?P=a),必需要写的分组里面,否则的不能叫分组命名了

    ret = re.search(r'<(?P<tab1>\w+)>(?P<content>\w+)<\\(\w+)>',r'<title>科比<\title>')
    print(ret.group(0)) # 不受到分组的影响
    print(ret.group('tab1')) # 不受到分组的影响
    print(ret.group('content')) # 不受到分组的影响

     特殊的需求:把这个字符串所有匹配出来<h1>wahaha</h2></h1>
    par = '<\w+>.*?</\w+>'
    ret = re.search('<(?P<tag>\w+)>.*</(?P=tag)>','<h1>wahaha</h2></h1></h3>')
    print(ret.group())

    par = '<\w+>.*?</\w+>'
    ret = re.search(r'<(\w+)>.*</\1(是使用第几个分组名字)>','<h1>wahaha</h2></h1></h3>')
    print(ret.group())

    当咱们要匹配的内容混在不想匹配的内容中
    只能把不想要的也匹配出来,而后去掉不想要的就是想要的

    下列我只想取整数部分
    ret = re.findall('\d+\.\d+|(\d+)','1-2*(60+(-40.35/5)-(-4*3))') #取出来不包含40.35,可是包含"",由于findall遇到分组是优先匹配,因此匹配到小数就放弃,可是必须得返回一个元素,就返回""
    ret = re.findall('\d+\.\d+|\d+','1-2*(60+(-40.35/5)-(-4*3))')  #取出来的包含40.35
    ret.remove('')
    print(ret)

碰见分组
    findall 优先显示分组中的内容
    split 保留被切掉的分组内的内容
    search 能够经过组的索引取值
    取消分组的特殊行为(?:正则)

常见的使用正则解决问题的方式#
  1.把整个结构描述下来,对想要的进行分组#
  2.把不想要的也匹配出来,而后用手段删掉

1. 数字:^[0-9]*$
2. n位的数字:^\d{n}$
3. 至少n位的数字:^\d{n,}$
4. m-n位的数字:^\d{m,n}$
5. 零和非零开头的数字:^(0|[1-9][0-9]*)$
6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
7. 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8. 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11. 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12. 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13. 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14. 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15. 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16. 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17. 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18. 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19. 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
2.校验字符的表达式
1. 汉字:^[\u4e00-\u9fa5]{0,}$
2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3. 长度为3-20的全部字符:^.{3,20}$
4. 由26个英文字母组成的字符串:^[A-Za-z]+$
5. 由26个大写英文字母组成的字符串:^[A-Z]+$
6. 由26个小写英文字母组成的字符串:^[a-z]+$
7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8. 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11. 能够输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12. 禁止输入含有~的字符:[^~\x22]+
3.特殊需求表达式
1. Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4. 手机号码(可根据目前国内收集号扩展前两位开头号码):^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5. 电话号码("XXX-XXXXXXX""XXXX-XXXXXXXX""XXX-XXXXXXX""XXX-XXXXXXXX""XXXXXXX""XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6. 国内电话号码(0511-440522二、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7.15位身份证号:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$
8.18位身份证号:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
9. 账号是否合法(字母开头,容许5-16字节,容许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
11. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12. 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
14. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
15. 钱的输入格式:
(1)有四种钱的表示形式咱们能够接受:"10000.00""10,000.00", 和没有 """10000""10,000":^[1-9][0-9]*$
(2)这表示任意一个不以0开头的数字,可是,这也意味着一个字符"0"不经过,因此咱们采用下面的形式:^(0|[1-9][0-9]*)$
(3)一个0或者一个不以0开头的数字.咱们还能够容许开头有一个负号:^(0|-?[1-9][0-9]*)$
(4)这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,由于钱总不能是负的吧.下面咱们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
(5)必须说明的是,小数点后面至少应该有1位数,因此"10."是不经过的,可是 "10""10.2" 是经过的:^[0-9]+(.[0-9]{2})?$
(6)这样咱们规定小数点后面必须有两位,若是你认为太苛刻了,能够这样:^[0-9]+(.[0-9]{1,2})?$
(7)这样就容许用户只写一位小数.下面咱们该考虑数字中的逗号了,咱们能够这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
(8)1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了"+"能够用"*"替代若是你以为空字符串也能够接受的话(奇怪,为何?)最后,别忘了在用函数时去掉去掉那个反斜杠,通常的错误都在这里
16. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
17. 中文字符的正则表达式:[\u4e00-\u9fa5]
18. 双字节字符:[^\x00-\xff] (包括汉字在内,能够用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
19. 空白行的正则表达式:\n\s*\r (能够用来删除空白行)
20. HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
21. 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (能够用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),很是有用的表达式)
22. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
23. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
24. IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
25. IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
常见的正则表达式

 other re.S和re.M

Python 的re模块内置函数几乎都有一个flags参数,以位运算的方式将多个标志位相加。其中有两个模式:单行(re.DOTALL, 或者re.S)和多行(re.MULTILINE, 或者re.M)模式。
它们初看上去很差理解,可是有时又会很是有用。这两个模式在PHP和JavaScripts里都有。

单行模式 re.DOTALL
在单行模式里,文本被强制看成单行来匹配,什么样的文本不会被看成单行?就是里面包含有换行符的文(或者是网页源码),好比:
This is the first line.\nThis is the second line.\nThis is the third line.
点号(.)能匹配全部字符,换行符例外。如今咱们但愿能匹配出整个字符串,当用点号(.)匹配上面这个字符串时,在换行符的地方,匹配中止。

1.在打印的时候直接打印出三行
print (a)
    This is the first line.
    This is the second line.
    This is the third line.
2.在不使用re.S的时候会按行匹配
  import re
  ret = re.findall('^This.*line',a)
  print(ret)
  在上面的例子里,即便是默认贪婪(greedy)的匹配,仍然在第一行的结尾初中止了匹配.
3.使用re.S的时候
  import re
  ret = re.findall('^This.*line',a,re.S)
  print(ret)
  而在单行模式下,换行符被看成普通字符,被点号(.)匹配.


多行模式 re.MULTILINE
在多行模式里,文本被强制看成多行来匹配。正如上面单行模式里说的,默认状况下,一个包含换行符的字符串老是被看成多行处理。可是行首符^和行尾符$仅仅匹配整个字符串的起始和结尾。
这个时候,包含换行符的字符串又好像被看成一个单行处理。
在下面的例子里,咱们但愿能将三句话分别匹配出来。用re.findall( )显示全部的匹配项
a = 'This is the first line.\nThis is the second line.\nThis is the third line.'
    
1.在打印的时候直接打印出三行
print (a)
    This is the first line.
    This is the second line.
    This is the third line.
2.在不使用re.S的时候会按行匹配
    import re
    ret = re.findall('^This.*line$',a)
    print(ret)
  默认点号不匹配换行符,因此匹配的为空
3.使用re.S的时候
  import re
  ret = re.findall('^This.*line',a,re.M)
  ret = re.findall('^This.*?line',a,re.M)
  print(ret)
  匹配出了整句话,由于默认是贪婪模式
4.用问号切换成非贪婪模式:
    仍然是整句话,这是由于^和$只匹配整个字符串的起始和结束。
    在多行模式下,^除了匹配整个字符串的起始位置,还匹配换行符后面的位置;$除了匹配整个字符串的结束位置,还匹配换行符前面的位置.

总结:在单行模式下,点号(.)匹配全部的字符,因此能够说,单行模式改变了点号(.)的匹配行为,在多行模式下,多行模式改变了^和$的匹配行为

 

 分组

 

 

 

返回系列

相关文章
相关标签/搜索