首先是文档说明:

>>> 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))

output

['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#第二类数量结构

)\s

(?:\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)
这时候填写进去的字符,就成了遇到则不匹配的条件。

而我的数词查找就需要这个功能,来实现避免数词出现在省略先行词从句的开头的情况。
当然下面这个表达式是不能运行的,必须放到之前那个大串里。

re.compile(r"""

(?!

(?:

\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]))

)

\b

)

)

#筛掉的特殊词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#第二类数量结构

)\s

(?!

(?:

\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]))

)

\b

)

)

#筛掉的特殊词(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)

最新文章

  1. GJM : 常用网站收集 【不断更新中... ... ... 】
  2. Oracle客户端配置
  3. spring-实现配置文件读取
  4. hdu 1348 (凸包求周长)
  5. MVC项目页面获取控制器的信息
  6. http://www.shengshiyouxi.com
  7. .net Framework各个版本之间的发展
  8. Vue深度学习(1)
  9. MongoDB 索引限制
  10. 记录一个pom文件
  11. Apollo 8 — ConfigService 异步轮询接口的实现
  12. ajaxmin.exe 命令参数
  13. Nlog日志之File
  14. http协议与常见状态码
  15. 关于RNA-Seq数据去接头(Adapter)这事需要讲一讲
  16. form表单组件
  17. 你的产品适不适合做微信小程序?你需要这篇产品逻辑分析
  18. MapReduce C++ Library
  19. nginx 学习笔记(5) nginx调试日志
  20. 支付机构MRC模

热门文章

  1. ubuntu16.04 dpkg强制安装 teamviewer
  2. DateUtil日期处理
  3. 原生nodejs 学习笔记2
  4. Session的作用和使用场景
  5. 02 Tensorflow的安装配置
  6. 如何打开Windows Server 2008 R2的域安全策略
  7. CentOS7系列搭建Openvpn
  8. linux sleep用法
  9. Alpha Level (Significance Level)
  10. python之socket运用1