python正则表达式或者python

Python 基础教程
Python正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
本章节主要介绍Python中常用的正则表达式处理函数。
re.match函数
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
print(re.match('www', '').span())
print(re.match('com', ''))
以上实例运行输出结果为:
line = &Cats are smarter than dogs&
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print &matchObj.group() : &, matchObj.group()
print &matchObj.group(1) : &, matchObj.group(1)
print &matchObj.group(2) : &, matchObj.group(2)
print &No match!!&
以上实例执行结果如下:
matchObj.group() :
Cats are smarter than dogs
matchObj.group(1) :
matchObj.group(2) :
re.search方法
re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法:
re.search(pattern, string, flags=0)
函数参数说明:
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.search方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
print(re.search('www', '').span())
print(re.search('com', '').span())
以上实例运行输出结果为:
line = &Cats are smarter than dogs&;
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print &searchObj.group() : &, searchObj.group()
print &searchObj.group(1) : &, searchObj.group(1)
print &searchObj.group(2) : &, searchObj.group(2)
print &Nothing found!!&
以上实例执行结果如下:
searchObj.group() :
Cats are smarter than dogs
searchObj.group(1) :
searchObj.group(2) :
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
line = &Cats are smarter than dogs&;
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print &match --& matchObj.group() : &, matchObj.group()
print &No match!!&
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print &search --& matchObj.group() : &, matchObj.group()
print &No match!!&
以上实例运行结果如下:
No match!!
search --& matchObj.group() :
检索和替换
Python 的 re 模块提供了re.sub用于替换字符串中的匹配项。
re.sub(pattern, repl, string, count=0, flags=0)
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
phone = & # 这是一个国外电话号码&
num = re.sub(r'#.*$', &&, phone)
print &电话号码是: &, num
num = re.sub(r'\D', &&, phone)
print &电话号码是 : &, num
以上实例执行结果如下:
电话号码是:
电话号码是 :
repl 参数是一个函数
以下实例中将字符串中的匹配的数字乘于 2:
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P&value&\d+)', double, s))
执行输出结果为:
A46G8HFD1134
正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符描述
re.I使匹配对大小写不敏感
re.L做本地化识别(locale-aware)匹配
re.M多行匹配,影响 ^ 和 $
re.S使 . 匹配包括换行在内的所有字符
re.U根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 '\\t')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
^匹配字符串的开头
$匹配字符串的末尾。
.匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...]用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...]不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re*匹配0个或多个的表达式。
re+匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n,}精确匹配n个前面表达式。
re{ n, m}匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b匹配a或b
(re)G匹配括号内的表达式,也表示一个组
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx)正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re) 类似 (...), 但是不表示一个组
(?imx: re)在括号中使用i, m, 或 x 可选标志
(?-imx: re)在括号中不使用i, m, 或 x 可选标志
(?#...)注释.
(?= re)前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re)前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?& re)匹配的独立模式,省去回溯。
\w 匹配字母数字及下划线
\W匹配非字母数字及下划线
\s 匹配任意空白字符,等价于 [\t\n\r\f].
\S匹配任意非空字符
\d 匹配任意数字,等价于 [0-9].
\D匹配任意非数字
\A匹配字符串开始
\Z匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
\z匹配字符串结束
\G匹配最后匹配完成的位置。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等.匹配一个换行符。匹配一个制表符。等
\1...\9匹配第n个分组的内容。
\10匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。
正则表达式实例
python匹配 "python".
[Pp]ython 匹配 "Python" 或 "python"
rub[ye]匹配 "ruby" 或 "rube"
[aeiou]匹配中括号内的任意一个字母
[0-9]匹配任何数字。类似于 []
[a-z]匹配任何小写字母
[A-Z]匹配任何大写字母
[a-zA-Z0-9]匹配任何字母及数字
[^aeiou]除了aeiou字母以外的所有字符
[^0-9]匹配除了数字外的字符
特殊字符类
.匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
\d匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
7个月前 (04-24)
记住登录状态
重复输入密码Python 正则表达式入门(初级篇)
本文主要为没有使用正则表达式经验的新手入门所写。
转载请写明出处
首先说 正则表达式是什么?
正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。
引用自维基百科https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F
定义是定义,太正经了就没法用了。我们来举个栗子:假如你在写一个爬虫,你得到了
一个网页的HTML源码。其中有一段
&html&&body&&h1&hello world&h1&&/body&&/html&
你想要把这个hello world提取出来,但你这时如果只会python 的字符串处理,那么第一反应可能是
s = &html&&body&&h1&hello world&h1&&/body&&/html&
start_index = s.find('&h1&')
然后从这个位置向下查找到下一个&h1&出现这样做未尝不可,但是很麻烦不是吗。需要考虑多个标签,一不留神就多匹配到东西了,而如果想要非常准确的匹配到,又得多加循环判断,效率太低。
这时候,正则表达式就是首选的帮手。
接着说我们刚才那个例子。我们如果拿正则处理这个表达式要怎么做呢?
key = r&&html&&body&&h1&hello world&h1&&/body&&/html&&#这段是你要匹配的文本
p1 = r&(?&=&h1&).+?(?=&h1&)&#这是我们写的正则表达式规则,你现在可以不理解啥意思
pattern1 = re.compile(p1)#我们在编译这段正则表达式
matcher1 = re.search(pattern1,key)#在源文本中搜索符合正则表达式的部分
print matcher1.group(0)#打印出来
你可以尝试运行上面的代码,看看是不是和我们想象的一样(博主是在python2.7环境下)发现代码挺少挺简单?往下看。而且正则表达式实际上要比看起来的那种奇形怪状要简单得多。
首先,从最基础的正则表达式说起。
假设我们的想法是把一个字符串中的所有&python&给匹配到。我们试一试怎么做
key = r&javapythonhtmlvhdl&#这是源文本
p1 = r&python&#这是我们写的正则表达式
pattern1 = re.compile(p1)#同样是编译
matcher1 = re.search(pattern1,key)#同样是查询
print matcher1.group(0)
看完这段代码,你是不是觉得:卧槽?这就是正则表达式?直接写上去就行?
确实,正则表达式并不像它表面上那么奇葩,如果不是我们故意改变一些符号的含义时,你看到的就是想要匹配的。
所以,先把大脑清空,先认为正则表达式就是和想要匹配的字符串长得一样。在之后的练习中我们会逐步进化
0.无论是python还是正则表达式都是区分大小写的,所以当你在上面那个例子上把&python&换成了&Python&,那就匹配不到你心爱的python了。
1.重新回到第一个例子中那个&h1&hello world&h1&匹配。假如我像这么写,会怎么样?
key = r&&h1&hello world&h1&&#源文本
p1 = r&&h1&.+&h1&&#我们写的正则表达式,下面会将为什么
pattern1 = re.compile(p1)
print pattern1.findall(key)#发没发现,我怎么写成findall了?咋变了呢?
有了入门级的经验,我们知道那两个&h1&就是普普通通的字符,但是中间的是什么鬼?
.字符在正则表达式代表着可以代表任何一个字符(包括它本身)
findall返回的是所有符合要求的元素列表,包括仅有一个元素时,它还是给你返回的列表。
机智如你可能会突然问:那我如果就只是想匹配&.&呢?结果啥都给我返回了咋整?在正则表达式中有一个字符\,其实如果你编程经验较多的话,你就会发现这是好多地方的“转义符”。在正则表达式里,这个符号通常用来把特殊的符号转成普通的,把普通的转成特殊的23333(并不是特殊的“2333”,写完才发现会不会有脑洞大的想歪了)。
举个栗子,(我的邮箱),你可以把正则表达式写成下面这个样子:
key = r&afiouwehrfuichuxiuhong@askdjhfiosueh&
p1 = r&chuxiuhong@hit\.edu\.cn&
pattern1 = re.compile(p1)
print pattern1.findall(key)
发现了吧,我们在.的前面加上了转义符\,但是并不是代表匹配“\.”的意思,而是只匹配“.”的意思!
不知道你细不细心,有没有发现我们第一次用.时,后面还跟了一个+?那这个加号是干什么的呢?
其实不难想,我们说了“.字符在正则表达式代表着可以代表任何一个字符(包括它本身)”,但是&hello world&可不是一个字符啊。
+的作用是将前面一个字符或一个子表达式重复一遍或者多遍。
比方说表达式“ab+”那么它能匹配到“abbbbb”,但是不能匹配到&a&,它要求你必须得有个b,多了不限,少了不行。你如果问我有没有那种“有没有都行,有多少都行的表达方式”,回答是有的。
*跟在其他符号后面表达可以匹配到它0次或多次
比方说我们在王叶内遇到了链接,可能既有http://开头的,又有https://开头的,我们怎么处理?
key = r& and &#胡编乱造的网址,别在意
p1 = r&https*://&#看那个星号!
pattern1 = re.compile(p1)
print pattern1.findall(key)
['http://', 'https://']
2.比方说我们有这么一个字符串&cat hat mat qat&,你会发现前面三个是实际的单词,最后那个是我胡编乱造的(上百度查完是昆士兰英语学院的缩写= =)。如果你本来就知道&at&前面是c、h、m其中之一时这才构成单词,你想把这样的匹配出来。根据已经学到的知识是不是会想到写出来三个正则表达式进行匹配?实际上不需要。因为有一种多字符匹方式
[]代表匹配里面的字符中的任意一个
还是举个栗子,我们发现啊,有的程序员比较过分,,在&html&&/html&这对标签上,大小写混用,老害得我们抓不到想要的东西,我们该怎么应对?是写16*16种正则表达式挨个匹配?no
key = r&lalala&hTml&hello&/Html&heiheihei&
p1 = r&&[Hh][Tt][Mm][Ll]&.+?&/[Hh][Tt][Mm][Ll]&&
pattern1 = re.compile(p1)
print pattern1.findall(key)
['&hTml&hello&/Html&']
我们既然有了范围性的匹配,自然有范围性的排除。
[^]代表除了内部包含的字符以外都能匹配
还是cat,hat,mat,qat这个例子,我们想匹配除了qat以外的,那么就应该这么写:
key = r&mat cat hat pat&
p1 = r&[^p]at&#这代表除了p以外都匹配
pattern1 = re.compile(p1)
print pattern1.findall(key)
为了方便我们写简洁的正则表达式,它本身还提供下面这样的写法
小写字母任意之一
大写字母任意之一
等同于[0-9]
等同于[^0-9]匹配非数字
等同于[a-z0-9A-Z_]匹配大小写字母、数字和下划线
等同于[^a-z0-9A-Z_]等同于上一条取非
3.介绍到这里,我们可能已经掌握了大致的正则表达式的构造方式,但是我们常常会在实战中遇到一些匹配的不准确的问题。比方说:
key = r&chuxiuhong@&
p1 = r&@.+\.&#我想匹配到@后面一直到“.”之间的,在这里是hit
pattern1 = re.compile(p1)
print pattern1.findall(key)
['@hit.edu.']
呦呵!你咋能多了呢?我理想的结果是@hit.,你咋还给我加量了呢?这是因为正则表达式默认是“贪婪”的,我们之前讲过,“+”代表是字符重复一次或多次。但是我们没有细说这个多次到底是多少次。所以它会尽可能“贪婪”地多给我们匹配字符,在这个例子里也就是匹配到最后一个“.”。
我们怎么解决这种问题呢?只要在“+”后面加一个“?”就好了。
key = r&chuxiuhong@&
p1 = r&@.+?\.&#我想匹配到@后面一直到“.”之间的,在这里是hit
pattern1 = re.compile(p1)
print pattern1.findall(key)
['@hit.']
加了一个“?”我们就将贪婪的“+”改成了懒惰的“+”。这对于[abc]+,\w*之类的同样适用。
小测验:上面那个例子可以不使用懒惰匹配,想一种方法得到同样的结果
**个人建议:在你使用&+&,&*&的时候,一定先想好到底是用贪婪型还是懒惰型,尤其是当你用到范围较大的项目上时,因为很有可能它就多匹配字符回来给你!!!**
为了能够准确的控制重复次数,正则表达式还提供
{a,b}(代表a&=匹配次数&=b)
还是举个栗子,我们有sas,saas,saaas,我们想要sas和saas,我们怎么处理呢?
key = r&saas and sas and saaas&
p1 = r&sa{1,2}s&
pattern1 = re.compile(p1)
print pattern1.findall(key)
['saas', 'sas']
如果你省略掉{1,2}中的2,那么就代表至少匹配一次,那么就等价于?
如果你省略掉{1,2}中的1,那么就代表至多匹配2次。
下面列举一些正则表达式里的元字符及其作用
代表任意字符
逻辑或操作符
匹配内部的任一字符或子表达式
对字符集和取非
定义一个区间
对下一字符取非(通常是普通变特殊,特殊变普通)
匹配前面的字符或者子表达式0次或多次
惰性匹配上一个
匹配前一个字符或子表达式一次或多次
惰性匹配上一个
匹配前一个字符或子表达式0次或1次重复
匹配前一个字符或子表达式
匹配前一个字符或子表达式至少m次至多n次
匹配前一个字符或者子表达式至少n次
前一个的惰性匹配
匹配字符串的开头
匹配字符串开头
匹配字符串结束
匹配一个控制字符
匹配任意数字
匹配数字以外的字符
匹配制表符
匹配任意数字字母下划线
不匹配数字字母下划线
中级篇介绍子表达式,向前向后查找,回溯引用 链接:
阅读(...) 评论()48被浏览7027分享邀请回答&&& import re
&&& help(re.findall)
Help on function findall in module re:
findall(pattern, string, flags=0)
Return a list of all non-overlapping matches in the string.
If one or more capturing groups are present in the pattern, return
a list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result.
意思很明显,分组匹配下(一对括号内是一个组),findall函数返回元组形式的匹配结果,并且匹配为空也会返回到元组中。所以一般用法是这样的:&&& a = "one two three four five six"
&&& import re
&&& b = re.findall(r"(one) (two) (three) (four) (five) (six)",a)#去掉了"|"号
&&& print(b)
[('one', 'two', 'three', 'four', 'five', 'six')]#按组将匹配结果添加到元组中返回
&&& b = re.findall(r"(one) (two) (three) (four)",a)
#不完全匹配
&&& print(b)
[('one', 'two', 'three', 'four')]
#按组返回匹配成功部分,列表长度为1
&&& b = re.findall(r"one|two|three|four|five|six",a)
#不安组的条件匹配
&&& print(b)
['one', 'two', 'three', 'four', 'five', 'six']#返回长度为6的列表
&&& b = re.findall(r"one two three four five six",a)
&&& print(b)
['one two three four five six'] #完全匹配,返回长度为1的列表
&&& b = re.findall(r"(one) (two) (three) (four) (five) (six) (seven)",a)
&&& print(b)
[]# 没法全部匹配,返回空
&&& print (re.findall(r"[abc]","abc"))#[]的效果
['a','b','c']
&&& print (re.findall(r"a|b|c","abc"))#"|"的效果
['a','b','c']
通过以上实验可以得出的结论:1条件匹配符"|"使得findall按每一种条件匹配一次,且"|"和"[]"效果是相同的,返回形式一样。2圆括号分组匹配使得findall返回元组,元组中,几对圆括号就有几个元素,保留空匹配。再看我提问中举的例子,将条件匹配与分组匹配结合在了一起。&&& a = "one two three four five six"
&&& b = re.findall("(one)|(two)|(three)|(four)|(five)|(six)",a)#加上了"|"号
&&& print(b)
[('one', '', '', '', '', ''), ('', 'two', '', '', '', ''),
('', '', 'three', '', '', ''),('', '', '', 'four', '', ''),
('', '', '', '', 'five', ''),('', '', '', '', '', 'six')]
于是就理解了:1这个结果是因为按组匹配所以有元组,每个元组都有六个元素。2而因为是条件匹配,列了六种匹配条件,于是findall匹配六次,结果列表有六个元素。3又因为每次匹配只能用一种条件,所以按组匹配结果列表中的每个元组只有一组有值而其他均为空。这有什么用呢?比如:&&& x = "3 min 46 sec 300 ms"
#分秒毫秒的提取
&&& print(re.findall(r"(\d{0,}) (min|sec|ms)",x))
[('3', 'min'), ('46', 'sec'), ('300', 'ms')] #会不会很方便?
--------------------------------------------------------------------------------------------------这个理解其实对下面那个问题(如何匹配某种单词搭配)没什么用,因为还有一个符号没有介绍,那就是"?:"符号,表示取消按分组返回。#这个正则式子是随意写就的,
#按照人的思维理解。
#这个式子匹配以h或s为开头,ef或cd的(a或b)结尾为结尾的东西。
#一共有2*2*2八种可能性,findall的结果会有八个元素。
&&& print(re.findall(r"\b((h|s)(ef|(cd|(a|b))))\b","sef scd sa sb hef hcd ha hb"))
#不添加?:符号时结果如下:
#正则式子中的括号一共有五个,所以返回列表里的每个元组有五个元素
[('sef', 's', 'ef', '', ''), ('scd', 's', 'cd', 'cd', ''),
('sa', 's', 'a', 'a', 'a'), ('sb', 's', 'b', 'b', 'b'),
('hef', 'h', 'ef', '', ''), ('hcd', 'h', 'cd', 'cd', ''),
('ha', 'h', 'a', 'a', 'a'), ('hb', 'h', 'b', 'b', 'b')]
#下面是加上"?:"的结果
&&&print(re.findall(r"\b(?:(?:h|s)(?:ef|(?:cd|(?:a|b))))\b","sef scd sa sb hef hcd ha hb"))
['sef', 'scd', 'sa', 'sb', 'hef', 'hcd', 'ha', 'hb']
第一个式子返回的结果其实也算OK,因为已经覆盖到了所有的可能,只不过冗余项比较多,想得到纯粹的结果还要处理一次。第二个式子加了"?:"后就简洁许多。作为初学者,可能用不到分组这么复杂的正则式子,也就更不用提取消分组的符号了,所以很多正则的入门教程并不会花太多时间在这两项上。所以现在就介绍一下如何解决匹配单词搭配的问题。就比如说找数量结构的词组吧。我们先进行书面的结构分析数量结构是一种表示数量关系的短语,比如汉语中的一斤酒一两牛肉,由数词+量词+名词构成,也可以是一下,轻轻一按,用力一踢,由副词/+数词+动词构成。在英语中数量结构又分为两种。第一种是 a/an + n1 + of + n2,其中n1、n2是名词。比如 a piece of bread 。这种结构往往用来修饰不可数名词。第二种是 num. + n 这个简单,就是数词+可数名词的复数形式,穷举所有的数词就行了。第一种的正则式很简单,是这样的:r"\ban{0,1}\b \b\w+\b \bof\b \b\w+\b" #凡是在不定冠词和of之间的必然是名词,在of之外的是名词
第二种就稍微复杂一点,我们要把所有的数词都列出来,寻找其中的规律差不多能分出这么几组没有规律的:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve twenty|forty)结尾可加teen也可不加的:(?:(?:four)(?:teen){0,1})结尾可加teen或ty也可不加的 :(?:(?:six|seven|eight|nine)|(?:ty|teen))结尾必须加teen或ty的: (?:(?:fif|thir)(?:ty|teen))把他们组合起来就是:r"(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve |twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b"
再加上第一种可能就成了:(?:\ban{0,1}\b \b\w+\b \bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b)
这还只是选了前部分,后面还要接一个名词,所以:(?:(?:\ban{0,1}\b \b\w+\b \bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b)) (?:\b\w+\b)
于是这就是是完成状态了,我们来检测一下成果吧:input
import rea = "a cup of tea million stars forty people "
b = re.compile(r"(?:(?:\ban{0,1}\b \b\w+\b \bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b)) (?:\b\w+\b)")
print(re.findall(b,a))
['a cup of tea', 'million stars', 'forty people']
这种眼花缭乱的式子,看着很麻烦,也不好解读,还好python提供了松散正则表达式。只要在re.comile的第二个参数上填上"re.VERBOSE"即可写成如'''example'''注释的形式,此时空格不再被匹配,必须使用\s表达(下面这个版本已经更新了,这次更新囊括了所有的序数词):a = "give me a kiss million stars one piece"
b = re.compile(r"""
#随时可以以#号备注
(?:\b\w+\b\s\b\w+\b\s)?
(?:\ban?\b\s\b\w+\b\s\bof\b)
|#第一类数量结构
(?:\b(?:one|two|three|five|first|second|third|fifth|sixth|an?))
|#fifth在这里 没有规律的数词 fifth sixth
(?:(?:hundred|thounsand|million|billion|trillion|ten|eleven|twel(?:f|ve))(?:th)?)
(?:(?:twent|fort)(?:y|ieth))
(?:(?:four)(?:teen|th)?)
|#加不加teen皆可的数词
(?:(?:six|seven|eight?|nine?)(?:(?:(?:t[yh])(?:eth)?)|(?:teen)(?:th)?)?)
|#加不加teen或ty皆可的数词
(?:(?:fif|thir)(?:(?:t[yi])(?:eth)?|(?:teen)(?:th)?))
#必须加teen或ty的数词 fifteen thirteen fifty thirty
fiftieth thirtieth fifteenth thirteenth
)\b#第二类数量结构
(?:\b\w+\b)#后跟的名词
""",re.VERBOSE)
这个式子到这里还是比较粗糙的,比如对于任何一文章中的“the one you”他都会当作数量结构匹配,所以还要增加一些其他条件来过滤这样的可能,不过我还没学到那个地步,所以我也没法解决这个问题,以后学会再来添加吧!更新一下:关键词:零宽断言。在python正则表达式中使用零宽断言,网上也有很多教程。简单说,零宽断言要完成的目标是:当字符串符合一定条件,则匹配某些字符。什么叫断言?一个断言就是对条件做出判断,相当于if判断结构,满足条件,则做某事,不过else只能是不匹配。什么叫零宽?也就是这个东西所占的匹配字符中的宽度是零,也就是不匹配本身。其他的关键词如零宽度正预测先行断言太复杂了我也不太清楚,就不讲了,会用就行。使用方法:exp(?=exp)在括号中使用?=后,这个括号内?=之后的字符就成了零宽断言所要判断的条件,前面括号之外的表达式则是判断满足条件要启用的匹配字符。举例:\w+(?=logy)该表达式匹配任意以logy结尾的单词,但是不匹配logy本身。如果要把这个判断放在前面,则要用:(?&=exp)exp举例:(?&=href=")http可以匹配href="开头的http,但是不包括href=",这样的操作也省去了爬虫清洗数据时的一部分压力。需要注意的是,前置的断言在python中不能使用不确定宽度的字符作为判断条件,必须确定字符的个数。所以如果你还想同时匹配(?&=src=")http,你不能写(?&=src="|href=")http,你可以写:(?:(?&=src=")|(?&=href="))http这是python实现的一个小缺陷。不过后置的就可以这么写http(?=src="|href=")接着我们还有满足条件不匹配的用法,也就是在?后面加!。前置的就成了(?!&=exp)后置的成了(?!=exp)这时候填写进去的字符,就成了遇到则不匹配的条件。而我的数词查找就需要这个功能,来实现避免数词出现在省略先行词从句的开头的情况。当然下面这个表达式是不能运行的,必须放到之前那个大串里。</pile(r"""
(?:[Yy]ou|[Tt]hey)(?:'re)?
I|to|with|in|[SsHh]h?e|[Ii]t
(?:[Tt]h)(?:is|at|e[sr]e|)
(?:(?:[Ww]h)(?:o[ms]?e?|ere|at|en|i[cl][he]))
#筛掉的特殊词you I he she it this there that those with to in which where what when while whose who whom
""",re.VERBOSE)
结合两者就是:En_value = re.compile(r"""
#随时可以以#号备注
#尾断言可以有不确定符号数的匹配,首断言不可以。
(?:\b\w+\b\s\b\w+\b\s)?
(?:\ban?\b\s\b\w+\b\s\bof\b)
|#第一类数量结构
(?:\b(?:one|two|three|five|first|second|third|fifth|sixth|an?))
|#fifth在这里 没有规律的数词 fifth sixth
(?:(?:hundred|thounsand|million|billion|trillion|ten|eleven|twel(?:f|ve))(?:th)?)
(?:(?:twent|fort)(?:y|ieth))
(?:(?:four)(?:teen|th)?)
|#加不加teen皆可的数词
(?:(?:six|seven|eight?|nine?)(?:(?:(?:t[yh])(?:eth)?)|(?:teen)(?:th)?)?)
|#加不加teen或ty皆可的数词
(?:(?:fif|thir)(?:(?:t[yi])(?:eth)?|(?:teen)(?:th)?))
#必须加teen或ty的数词 fifteen thirteen fifty thirty
fiftieth thirtieth fifteenth thirteenth
)\b#第二类数量结构
(?:[Yy]ou|[Tt]hey)(?:'re)?
I|to|with|in|[SsHh]h?e|[Ii]t
(?:[Tt]h)(?:is|at|e[sr]e|)
(?:(?:[Ww]h)(?:o[ms]?e?|ere|at|en|i[cl][he]))
#筛掉的特殊词(you I he she it this there that those with to in which where what when while whose who whom
(?:\b\w+\b)#后跟的名词
""",re.VERBOSE)
好了这个问题的回答就完整了395 条评论分享收藏感谢收起

我要回帖

更多关于 正则表达式语法 的文章

 

随机推荐