鱼C论坛

 找回密码
 立即注册
查看: 2807|回复: 5

[技术交流] python正则表达式

[复制链接]
发表于 2017-6-22 01:11:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Messj 于 2017-6-23 12:06 编辑

最近,在看《python核心编程》这本书。开始学习正则表达式,第一次接触这个概念。我就一边学,一边分享。这个帖子就不设回复。如果有疑问,可以提出来,我尽力解答。如果想支持我,双击屏幕666(哈哈,玩笑话!)。如果觉得不错的话,就评个分吧。

本文未经本人许可,不得转载

一、正则表达式的起源

注 . 摘自百度百科。

正则表达式的“鼻祖”或许可一直追溯到科学家对人类神经系统工作原理的早期研究。美国新泽西州的Warren McCulloch和出生在美国底特律的Walter Pitts这两位神经生理方面的科学家,研究出了一种用数学方式来描述神经网络的新方法,他们创造性地将神经系统中的神经元描述成了小而简单的自动控制元,从而作出了一项伟大的工作革新。
在1951 年,一位名叫Stephen Kleene的数学科学家,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是《神经网事件的表示法》的论文,利用称之为正则集合的数学符号来描述此模型,引入了正则表达式的概念。正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式,因而采用了“正则表达式”这个术语。
之后一段时间,人们发现可以将这一工作成果应用于其他方面。Ken Thompson就把这一成果应用于计算搜索算法的一些早期研究,Ken Thompson是 Unix的主要发明人,也就是大名鼎鼎的Unix之父。Unix之父将此符号系统引入编辑器QED,然后是Unix上的编辑器ed,并最终引入grep。Jeffrey Friedl 在其著作《Mastering Regular Expressions (2nd edition)》(中文版译作:精通正则表达式,已出到第三版)中对此作了进一步阐述讲解,如果你希望更多了解正则表达式理论和历史,推荐你看看这本书。
自此以后,正则表达式被广泛地应用到各种UNIX或类似于UNIX的工具中,如大家熟知的Perl。Perl的正则表达式源自于Henry Spencer编写的regex,之后已演化成了pcre(Perl兼容正则表达式Perl Compatible Regular Expressions),pcre是一个由Philip Hazel开发的、为很多现代工具所使用的库。正则表达式的第一个实用应用程序即为Unix中的 qed 编辑器。
然后,正则表达式在各种计算机语言或各种应用领域得到了广大的应用和发展,演变成为计算机技术森林中的一只形神美丽且声音动听的百灵鸟。
以上是关于正则表达式的起源和发展的历史描述,如今正则表达式在基于文本的编辑器和搜索工具中依然占据着一个非常重要的地位。


二、正则表达式的概念及目的

这里先说个简单的概念和目的吧!正则表达式就是一组由字符和特殊符号组成的字符串,用于匹配符合需要的字符串(可以是一组,也可以是多组),它代表一种规则,一种模式。(下文会常用到该模式这个词句,意思就是这种正则表达式)

注 . 参考百度百科及菜鸟驿站。

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于对静态文本执行简单搜索和替换任务可能已经足够了,但它缺乏灵活性,若采用这种方法搜索动态文本,即使不是不可能,至少也会变得很困难。
通过使用正则表达式,可以:
测试字符串内的模式。
例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
基于模式匹配从字符串中提取子字符串。
可以查找文档内或输入域内特定的文本。
例如,您可能需要搜索整个网站,删除过时的材料,以及替换某些 HTML 格式标记。在这种情况下,可以使用正则表达式来确定在每个文件中是否出现该材料或该 HTML 格式标记。此过程将受影响的文件列表缩小到包含需要删除或更改的材料的那些文件。然后可以使用正则表达式来删除过时的材料。最后,可以使用正则表达式来搜索和替换标记。


三、最简单的正则表达式
其实我们平日里,就有接触过正则表达式这个概念。现在,从最简单最基础的说起。
以下表一为几个正则表达式和它们所匹配的字符串。该模式没有使用任何特殊符号,只有简单的字符。因此,其功能就像表格所体现的那么简单,就是匹配包含这一正则表达式的字符串。即正则表达式模式是“foo”,能匹配的只有包含“foo”的字符串。

表一
正则表达式模式 匹配的字符串
foo foo
Python Python
abc123 abc123


四、元字符
我们最常见的字符和特殊符号就是元字符。正是元字符给予了正则表达式强大的功能和灵活性。表二为常见的元字符(见三楼,很重要)。
五、python中re模块
Python是通过re模块来使用正则多项式。此处将重点介绍re模块。re模块中大多数函数也与已经编译的正则表达式对象(regex object)和正则匹配对象(regex match object)的方法同名且具有相同功能。

1.compile()——超级重要

(1)预编译与编译
预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等。就是为编译做的预备工作的阶段,主要处理#开始的预编译指令。
编译(compilation , compile) 1、利用编译程序从源语言编写的源程序产生目标程序的过程。 2、用编译程序产生目标程序的动作。 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。

(2)compile官方说明中文版
       将source编译为一段代码或AST对象。代码对象能够由exec语句执行或是通过调用 eval()求值。source既能是一个字符串也是一个AST对象。有关如何使用AST对象的信息,请参阅ast模块文档。
       filename参数应该给出需要被读取代码的文件;如果被读取代码并非来自文件,则需要传递一些可识别的值(常用的有'<string>' ).
       mode参数应该指定必须被编译的代码种类:如果source由一系列语句组成,则为“exec”,如果它由单个表达式组成,则为“eval”,如果它由单个交互式语句组成,则为“single”(在后一种情况下,可求值的表达式语句(除了None)将被打印)
       可选参数flags和dont_inherit控制哪些未来语句(参见PEP 236)会影响源的编译。 如果两者都不存在(或两者均为零),那么代码将被编译为在调用compile的代码中有效的那些将来的语句。 如果指定了flags参数,并且dont_inherit不是(或为零),那么除了将要使用的那些之外,还会使用       flags参数指定的将来的语句。 如果dont_inherit是一个非零整数,那么flags参数就是它 - 将被忽略在调用编译时有效的将来的语句。
       将来的语句由比特来指定,这些比特可以按位OR来一起指定多个语句。 指定给定功能所需的位域可以作为__future__模块中_Feature实例上的compiler_flag属性找到。
       如果编译的source无效,此函数会引发SyntaxError,如果源包含空字节,则此函数将引发TypeError。注意在“single”或“eval”模式下用多行代码编译字符串时,输入必须至少被一个换行字符终止。 这是为了便于在代码模块中检测不完整和完整的语句。

(3)compile用法
  1. >>> code = "for i in range(0, 10): print i"
  2. >>> cmpcode = compile(code, '', 'exec')
  3. >>> exec cmpcode
  4. 0
  5. 1
  6. 2
  7. 3
  8. 4
  9. 5
  10. 6
  11. 7
  12. 8
  13. 9
  14. >>> str = "3 * 4 + 5"
  15. >>> a = compile(str,'','eval')
  16. >>> eval(a)
  17. 17
复制代码


以上用法为其常见用法之一。下面介绍compile()关于正则表达式的常用用法:
  1. >>> import re
  2. >>>
  3. >>> pattern=re.compile('hello')
  4. >>> match=pattern.match('hello world!')
  5. >>> if match:
  6.         print match.group()

  7.        
  8. hello
复制代码


2.group()与groups()
匹配对象有两个主要的方法:group()与groups()
group()要么返回整个匹配对象,要么根据要求返回特定子组。
groups()则返回唯一的或全部的子组的元组。
如果没有子组的要求,当group()仍然返回整个匹配时,groups()返回一个空元组。

3.match()
match()试图从字符串的起始部位对模式进行匹配。如果匹配成功,就返回一个匹配对象;如果失败,就返回None;
  1. >>> import re
  2. >>> m=re.match('foo','foo')
  3. >>> if m is not None:
  4.         m.group()

  5.        
  6. 'foo'
  7. >>> m
  8. <_sre.SRE_Match object at 0x0000000002DF2E68>
  9. >>> m=re.match('foo','bar')
  10. >>> if m is not None:
  11.         m.group

  12.        
  13. >>> m=re.match('foo','food on the table')
  14. >>> m.group()
  15. 'foo'
  16. >>>
复制代码


4.search()
search()会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。
  1. >>> import re
  2. >>> re.search('foo','seafood').group()
  3. 'foo'
复制代码


(1)匹配多个字符串
  1. >>> import re
  2. >>> bt='bat|bet|bct'
  3. >>> m=re.match(bt,'bat')
  4. >>> if m is not None:
  5.         m.group()

  6.        
  7. 'bat'
  8. >>> m=re.match(bt,'blt')
  9. >>> if m is not None:
  10.         m.group()

  11.        
  12. >>> m=re.search(bt,'He bat a')
  13. >>> if m is not None:
  14.         m.group()

  15. 'bat'
  16. >>> m=re.match(bt,'He bat a')
  17. >>> if m is not None:
  18.         m.group()

  19.        
  20. >>>
复制代码

(2)匹配任何单个字符
  1. >>> anyend='.end'
  2. >>> m=re.match(anyend,'bend')
  3. >>> if m is not None:
  4.         m.group()

  5.        
  6. 'bend'
  7. >>> m=re.match(anyend,'end')#点号没有匹配到任何字符
  8. >>> if m is not None:
  9.         m.group()

  10.        
  11. >>> m=re.match(anyend,'\nend')#点号不匹配‘\n’
  12. >>> if m is not None:
  13.         m.group()

  14.        
  15. >>> m=re.search(anyend,'The end')
  16. >>> if m is not None:
  17.         m.group()

  18.        
  19. ' end'
  20. >>>
复制代码

(3)创建字符集([])
  1. >>> m=re.match('[cr][23][dp][o2]','c2po')
  2. >>> if m is not None:
  3.         m.group()

  4.        
  5. 'c2po'
复制代码

评分

参与人数 2鱼币 +12 收起 理由
康小泡 + 5
小甲鱼 + 7 支持楼主!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-6-22 01:12:33 | 显示全部楼层
本帖最后由 Messj 于 2017-6-23 12:13 编辑

(4)重复、特殊字符及分组
  1. >>> patt='\w+@(\w+\.)?\w+\.com'
  2. >>> re.match(patt,'nobody@xxx.com').group()
  3. 'nobody@xxx.com'
  4. >>> re.match(patt,'nobody@www.xxx.com').group()
  5. 'nobody@www.xxx.com'
  6. >>>
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-6-22 01:13:10 | 显示全部楼层
本帖最后由 Messj 于 2017-6-22 18:53 编辑

抢!

表二
表示法 描述 模式示例 示例匹配字符串
literal 匹配字符串的字面值literal foo foo
re1|re2 匹配正则表达式re1或re2 foo|bar foo或bar
.(dot) 匹配任何字符,换行符除外 a.a 如aaa,aba,a1a,a#a,匹配带开头是a中间任意结尾是a的字符串
^ 匹配字符串的开始 ^Head 匹配以Head开头的字符串,如Head1、Headask
$ 匹配字符串的结尾 docx$ 匹配以docx为结尾的字符串,如新建文档.docx
* 匹配前面出现零次或多次的正则表达式 [A-Za-z0-9]* 空字符串或由以A-Z,a-z,0-9为字符长度不小于2的字符串
+ 匹配前面出现一次或多次的正则表达式 [a-z]+\.com 如baidu.com,qq.com之类的
? 匹配前面出现零次或一次的正则表达式 goo? go或goo
{N} 匹配N次前面出现的正则表达式 [0-9]{3} 匹配三位数字,如123,856,001,090
{M,N} 匹配M-N次前面出现的正则表达式 [0-9]{15,16} [0-9]{15,16} 15位或16为的数字序列
[...] 匹配来自字符集里任意单一字符 [aeiou] 匹配以a、e、i、o、u范围内单个字符组成的字符串
[..x-y..] 匹配x-y范围内的任意单一字符 [0-9] 匹配以x至y范围内单个字符组成的字符串
[^...] 不匹配字符集里任意单一字符 [^aeiou] 匹配以a、e、i、o、u范围外单个字符组成的字符串
(...) 匹配封闭的正则表达式,然后另存为子组 f(oo|u)bar foobar、fubar
\d 匹配任何十进制的数,与[0,9]一致(\D与\d相反 ) data\d+\.txt匹配如data1.txt、data02.txt等


此表尚未填写完毕
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-6-22 01:14:46 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-6-22 01:16:36 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-6-23 11:15:00 | 显示全部楼层
更新自顶
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 13:00

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表