您的位置:首页 > 编程语言 > Python开发

【Python】正则表达式详解札记

2016-11-20 20:11 204 查看
【Python】正则表达式详解札记
一、什么是正则表达式?

正则表达式又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。

很多编程语言都内置了对正则表达式的支持,如Python、Perl、Java、C#、Javascript、PHP等。

常见的正则表达式使用场景有检查邮箱地址、URL有效性等等,当然还有分词(例如Java中的split函数)等。

下图展示了使用正则表达式进行匹配的流程: 



正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。

二、正则表达式的使用

下面以Python语法来介绍正则表达式的用法,其他语言大同小异。正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同;但不用担心,不被支持的语法通常是不常用的部分。

2.1正则表达式语法介绍

下图列出了Python支持的正则表达式元字符和语法:   



2.2 数量词的贪婪模式与非贪婪模式

正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"。

2.3 匹配模式

正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等,这部分内容将在Pattern类的工厂方法re.compile(pattern[, flags])中一起介绍。

2.4 re模块

2.4.1开始使用re

Python通过re模块提供对正则表达式的支持。使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。

# encoding: UTF-8

import re

# 将正则表达式编译成Pattern对象

pattern = re.compile(r'hello')

# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None

match = pattern.match('hello world!')

if match:

# 使用Match获得分组信息

    print (match.group())

### 输出 ###

# hello



 re.compile(strPattern[, flag]):
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。
第二个参数flag是匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。 
可选值有:

re.A(re.ASCII): 使\b、\B、\s、\S、\w和\W都假定字符串为ASCII(括号内是完整写法,下同)

re.I(re.IGNORECASE): 忽略大小写

re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(使^在起始处并在每个换行符后匹配,使$在结尾处但在每个换行符之前匹配)

re.S(DOTALL): 点任意匹配模式,改变'.'的行为,使.匹配任意字符(包括换行符)

re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的:

a = re.compile(r"""\d +  # the integral part

         \.    # the decimal point

         \d *  # some fractional digits""", re.X)

b = re.compile(r"\d+\.\d*")

 
re提供了众多模块方法用于完成正则表达式的功能。这些方法可以使用Pattern实例的相应方法替代,唯一的好处是少写一行re.compile()代码,但同时也无法复用编译后的Pattern对象。如上面这个hello world例子可以简写为:

m = re.match(r'hello', 'hello world!')

print (m.group())

 
2.5 实例

2.5.1点号匹配






2.5.2 \匹配




2.5.3 […]匹配






2.5.4 \d、\D 匹配








2.5.5 \s、\S 匹配




 







2.5.6 \w、\W 匹配






2.5.7 数量词匹配

2.5.7.1 数量词贪婪模式匹配

*号(匹配前一个字符(或分组)0次或无限次)>=0:









 
+号(匹配前一个字符(或分组)1次或无限次)>=1:







?号(匹配前一个字符(或分组)0次或1次)0 <= x <= 1:







{m}(匹配前一个字符(或分组)m次):





{m, n}(匹配前一个字符(或分组)m至n次):



2.5.7.2 数量词非贪婪模式匹配

*?、+?、? ?、{m,n}?









2.5.8 边界匹配

^(匹配字符串的开头、多行模式下匹配每一行的开头)、$(匹配字符串的结尾、多行模式下匹配每一行的结尾)、\A(仅匹配字符串开头)、\Z(仅匹配字符串结尾)、\b(匹配任何单词边界)、\B(匹配任何非单词边界)





 







多行模式匹配开头和结尾



这里匹配到hello后便返回,按照理解多行模式下应该继续向下匹配,但根本不存在组1。是因为search和match方法是匹配到就返回,而不是去匹配所有。



使用findall函数就会发现的确会匹配两次,也就是继续向下匹配了一次。













2.5.9 逻辑、分组匹配

|、(…)、(?P<name>…)、\<number>、(?P=name)





2.5.9 特殊构造(不作为分组)匹配

(?:…)、(?aimsx)、(?#...)、(?=…)、(?!...)、(?<=…)、(?<!...)、(?(name/id)yes-pattern|no-pattern)

(?:…)用到(?:…|…)表示只匹配一次,所以后面的数字引用不再起作用





 
(?:…)用到(?:…){m}表示只匹配m次,后面的数字引用不再起作用





(?aimsx)用在正则表达式开头和re.compile(strPattern[, flag])中[, flag]作用一样



(?#...)#后的内容作为注释忽略,在正则表达式中添加注释用



(?=…)正前瞻、(?!...)负前瞻、(?<=…)正回顾、(?<!...)负回顾







 

 

 



报错指出正回顾需要跟固定宽度模式,修正一下。



 



负回顾报错一样的信息



(?(name/id)yes-pattern|no-pattern)





从上面发现no-pattern还是不能匹配,这里没有实验成功,较为疑惑。

2.6 实际使用

说说最近我对正则表达式的使用。我特意制作了两个PY小工具。

由于送出的翻译需要统计每个字符串的长度,累计大几百行字符串,这个时候看到strings.xml自然发现这些字符串非常有规律,实际上是非常规整的xml文件。可以采用两种方式实现对字符串中有用数据的提取,其一为使用标准的解析xml库去实现;其二是自己使用正则表达式去解析这些有规律的字符串。我选择后者去实现,最终直接生成excel。具体参见PY脚本。

还是继续说strings.xml中的字符串,在开发即将结束的时候,由于移植等原因或者忘记删除没用的字符串,会出现大量"垃圾字符串",这些字符串站着地方,但没有实际用途了,由于数量较多就想到使用PY脚本简单处理。首先需要使用Android Lint工具在AS下生成对应的带处理文件,将AS下的输出粘贴到TXT待处理,解析这个TXT文件,删除strings.xml中无用字符串,采用操作xml库实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: