(一)正则表达式

基本规则:

  • ^ 匹配字符串开始位置。
  • $ 匹配字符串结束位置。
  • \b 匹配一个单词边界。
  • \d 匹配一个数字。
  • \D 匹配一个任意的非数字字符。
  • x? 匹配可选的x字符。换句话说,就是0个或者1个x字符。
  • x* 匹配0个或更多的x。
  • x+ 匹配1个或者更多x。
  • x{n,m} 匹配n到m个x,至少n个,不能超过m个。
  • (a|b|c) 匹配单独的任意一个a或者b或者c。
  • (x) 这是一个组,它会记忆它匹配到的字符串。你可以用re.search返回的匹配对象的groups()函数来获取到匹配的值。
  • [abc] 匹配a b c 中的一个
  • [^abc] 除了 a、 b 或 c 之外的任何字符

案例1:罗马数字

在罗马数字中,有七个不同的数字可以以不同的方式结合起来表示其他数字。

  • I = 1
  • V = 5
  • X = 10
  • L = 50
  • C = 100
  • D = 500
  • M = 1000

下面是几个通常的规则来构成罗马数字:

  • 大部分时候用字符相叠加来表示数字。I是1, II是2, III是3。VI是6(挨个看来,是“5 和 1”的组合),VII是7,VIII是8。
  • 含有10的字符(I,X,C和M)最多可以重复出现三个。为了表示4,必须用同一位数的下一个更大的数字5来减去一。不能用IIII来表示4,而应该是IV(意思是比5小1)。40写做XL(比50小10),41写做XLI,42写做XLII,43写做XLIII,44写做XLIV(比50小10并且比5小1)。
  • 有些时候表示方法恰恰相反。为了表示一个中间的数字,需要从一个最终的值来减。比如:9需要从10来减:8是VIII,但9确是IX(比10小1),并不是VIII(I字符不能重复4次)。90是XC,900是CM。
  • 表示5的字符不能在一个数字中重复出现。10只能用X表示,不能用VV表示。100只能用C表示,而不是LL。
  • 罗马数字是从左到右来计算,因此字符的顺序非常重要。DC表示600,而CD完全是另一个数字400(比500小100)。CI是101,IC不是一个罗马数字(因为你不能从100减1,你只能写成XCIX,表示比100小10,且比10小1)

可以从千位开始表示:

pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'

转为松散正则表达式,

>>> pattern = '''
^ # beginning of string
M{0,3} # thousands - 0 to 3 Ms
(CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
# or 500-800 (D, followed by 0 to 3 Cs)
(XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
# or 50-80 (L, followed by 0 to 3 Xs)
(IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
# or 5-8 (V, followed by 0 to 3 Is)
$ # end of string
'''

re.search(pattern, 'M', re.VERBOSE)

注意,如果要使用松散正则表达式,需要传递一个叫re.VERBOSE的参数

案例2:电话格式

  • 800-555-1212
  • 800 555 1212
  • 800.555.1212
  • (800) 555-1212
  • 1-800-555-1212
  • 800-555-1212-1234
  • 800-555-1212x1234
  • 800-555-1212 ext. 1234
  • work 1-(800) 555.1212 #1234
>>> phonePattern = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')  ①
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() ②
('', '', '', '')
>>> phonePattern.search('800-555-1212') ③
('', '', '', '')
>>> phonePattern.search('') ④
('', '', '', '')
>>> phonePattern = re.compile(r'''
# don't match beginning of string, number can start anywhere
(\d{3}) # area code is 3 digits (e.g. '800')
\D* # optional separator is any number of non-digits
(\d{3}) # trunk is 3 digits (e.g. '555')
\D* # optional separator
(\d{4}) # rest of number is 4 digits (e.g. '1212')
\D* # optional separator
(\d*) # extension is optional and can be any number of digits
$ # end of string
''', re.VERBOSE)
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() ①
('', '', '', '')

案例3:复数名词

  • 如果某个单词以 S 、X 或 Z 结尾,添加 ES 。Bass 变成 basses, fax 变成 faxes,而 waltz 变成 waltzes
  • 如果某个单词以发音的 H 结尾,加 ES;如果以不发音的 H 结尾,只需加上 S 。什么是发音的 H ?指的是它和其它字母组合在一起发出能够听到的声音。因此 coach 变成 coaches 而 rash 变成 rashes,因为在说这两个单词的时候,能够听到 CH 和 SH 的发音。但是 cheetah 变成 cheetahs,因为 H 不发音。
  • 如果某个单词以发 I 音的字母 Y 结尾,将 Y 改成 IES;如果 Y 与某个原因字母组合发其它音的话,只需加上 S 。因此 vacancy 变成 vacancies,但 day 变成 days 。
  • 如果所有这些规则都不适用,只需加上 S 并作最好的打算。
def plural(noun):
if re.search('[sxz]$', noun):
return re.sub('$', 'es', noun) ①
elif re.search('[^aeioudgkprt]h$', noun): ②
return re.sub('$', 'es', noun)
elif re.search('[^aeiou]y$', noun): ③
return re.sub('y$', 'ies', noun)
else:
return noun + 's'
>>>re.sub('([^aeiou])y$', r'\1ies','vacancy') 

'vacancies'

\1,它表示“嘿,记住的第一个分组呢?把它放到这里。”在此例中, 记住了 y 之前的 c ,在进行替换时,将用 c 替代 c,用 ies 替代 y 。(如果有超过一个的记忆分组,可以使用 \2 和\3 等等。)

(二)闭合

在动态函数中使用外部参数值的技术称为 闭合【closures】

import re

def match_sxz(noun):
return re.search('[sxz]$', noun) def apply_sxz(noun):
return re.sub('$', 'es', noun) def match_h(noun):
return re.search('[^aeioudgkprt]h$', noun) def apply_h(noun):
return re.sub('$', 'es', noun) def match_y(noun): ①
return re.search('[^aeiou]y$', noun) def apply_y(noun): ②
return re.sub('y$', 'ies', noun) def match_default(noun):
return True def apply_default(noun):
return noun + 's' rules = ((match_sxz, apply_sxz), ③ # rules 数据结构——一个函数对的序列
(match_h, apply_h),
(match_y, apply_y),
(match_default, apply_default)
) def plural(noun):
for matches_rule, apply_rule in rules:
if matches_rule(noun):
return apply_rule(noun)

匹配模式列表:

import re

def build_match_and_apply_functions(pattern, search, replace):
def matches_rule(word): ①
return re.search(pattern, word)
def apply_rule(word): ②
return re.sub(search, replace, word)
return (matches_rule, apply_rule) ③

如何调用这个函数呢:

patterns = \                                                        ①
(
('[sxz]$', '$', 'es'),
('[^aeioudgkprt]h$', '$', 'es'),
('(qu|[^aeiou])y$', 'y$', 'ies'),
('$', '$', 's') ②
)
rules = [build_match_and_apply_functions(pattern, search, replace) ③
for (pattern, search, replace) in patterns]

patterns 为字符串 的元组的元组

rules 为一个元组列表,每个元组都是一对函数

匹配模式文件

将规则放在独立的文件中,便于维护。

[plural4-rules.txt]

[sxz]$               $    es
[^aeioudgkprt]h$     $    es
[^aeiou]y$          y$    ies
$                    $    s
import re

def build_match_and_apply_functions(pattern, search, replace):  ①
def matches_rule(word):
return re.search(pattern, word)
def apply_rule(word):
return re.sub(search, replace, word)
return (matches_rule, apply_rule) rules = []
with open('plural4-rules.txt', encoding='utf-8') as pattern_file: ② #with 语句创建了叫做 context【上下文】的东西:当 with 块结束时,Python 将自动关闭文件
for line in pattern_file: ③
pattern, search, replace = line.split(None, 3) ④ #None 代表空格或者制表符,3表示只取前3个
rules.append(build_match_and_apply_functions( ⑤
pattern, search, replace))

(二)生成器

>>> def make_counter(x):
print('entering make_counter')
while True:
print('-'*50)
yield x
print('incrementing x %d' % (x))
x = x+1 >>> counter = make_counter(2) #仅仅调用,未执行
>>> counter #返回了一个生成器对象
<generator object make_counter at 0x00F7B5F8>
>>> next(counter) #next() 函数以一个生成器对象为参数,并返回其下一个值
entering make_counter
--------------------------------------------------
2
>>> next(counter)
incrementing x 2
--------------------------------------------------
3 #停止在yield位置

*  “yield” 暂停一个函数。“next()” 从其暂停处恢复其运行。

斐波那奇生成器

def fib(max):
a, b = 0, 1 ①
while a < max:
yield a ②
a, b = b, a + b ③
>>> for n in fib(1000):      ①
... print(n, end=' ') ②
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> list(fib(1000)) ③ #将一个生成器传递给 list() 函数,它将遍历整个生成器,并返回所有数值的列表
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]


Python 学习笔记(四)正则、闭合、生成器的更多相关文章

  1. python学习笔记四 迭代器,生成器,装饰器(基础篇)

    迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...

  2. python学习笔记(四):生成器、内置函数、json

    一.生成器 生成器是什么?其实和list差不多,只不过list生成的时候数据已经在内存里面了,而生成器中生成的数据是当被调用时才生成呢,这样就节省了内存空间. 1. 列表生成式,在第二篇博客里面我写了 ...

  3. Python学习笔记5-闭合与生成器

    >>> import re >>> re.search('[abc]','mark') <_sre.SRE_Match object; span=(1, 2) ...

  4. Python学习笔记四

    一.装饰器 1.知识储备 函数对象 函数可以被引用 函数可以当参数传递 返回值可以是函数 可以当作容器的元素 def func1(): print (666) def func2(): print ( ...

  5. 【Python学习笔记四】获取html内容之后,如何提取信息:使用正则表达式筛选

    在能够获取到网页内容之后,发现内容很多,那么下一步要做信息的筛选,就和之前的筛选图片那样 而在python中可以通过正则表达式去筛选自己想要的数据 1.首先分析页面内容信息,确定正则表达式.例如想获取 ...

  6. python学习笔记——列表生成式与生成器

    1.列表生成式(List Comprehensions) python中,列表生成式是用来创建列表的,相较于用循环实现更为简洁.举个例子,生成[1*1, 2*2, ... , 10*10],循环用三行 ...

  7. Python学习笔记(四)Python函数的参数

    Python的函数除了正常使用的必选参数外,还可以使用默认参数.可变参数和关键字参数. 默认参数 基本使用 默认参数就是可以给特定的参数设置一个默认值,调用函数时,有默认值得参数可以不进行赋值,如: ...

  8. Python学习笔记010_迭代器_生成器

     迭代器 迭代就类似于循环,每次重复的过程被称为迭代的过程,每次迭代的结果将被用来作为下一次迭代的初始值,提供迭代方法的容器被称为迭代器. 常见的迭代器有 (列表.元祖.字典.字符串.文件 等),通常 ...

  9. Python学习笔记四:面向对象编程

    一:定义类并创建实例 Python中定义类,通过class关键字,类名开头大写,参数列表为所继承的父类.如果没有需要明确继承的类,则继承object. 使用类来创建对象,只需 类名+() 形式即可,p ...

  10. python学习笔记(四) 思考和准备

    一.zip的坑 zip()函数接收多个可迭代数列,将数列中的元素重新组合,在3.0中返回迭代器指向 数列首地址,在3.0以下版本返回List类型的列表数列.我用的是3.5版本python, 所以zip ...

随机推荐

  1. WCF入门(四)---WCF架构

    WCF是一个分层架构,为开发各种分布式应用的充分支持.该体系结构在下面将详细说明. 约定 约定层旁边就是应用层,并含有类似于现实世界的约定,指定服务和什么样的信息可以访问它会使操作的信息.约定基本都是 ...

  2. linux用dd测试磁盘速度

    [root@localhost ~]# time dd if=/dev/zero bs=1024 count=1000000 of=/1Gb.file记录了1000000+0 的读入记录了100000 ...

  3. linux系统的文件类型学习

    linux是一个文件型操作系统,在linux下一切皆文件. 目录.字符设备.块设备.管道.套接字.符号连接文件等在linux下统统都是文件. linux下的文件类型分为以下几种类型: 1. 正规文件, ...

  4. (五)CSS伪类(Pseudo-class)

    CSS伪类用于向某些选择器添加特殊的效果.伪类的语法如下: selector : pseudo-class {property: value} CSS类也可以与伪类搭配使用: selector.cla ...

  5. C语言中的宏展开

    #include<stdio.h> #define f(a,b) a##b #define g(a) #a #define h(a) g(a) int main() { printf(,) ...

  6. poj 3264 Balanced Lineup (RMQ算法 模板题)

    RMQ支持操作: Query(L, R):  计算Min{a[L],a[L+1], a[R]}. 预处理时间是O(nlogn), 查询只需 O(1). RMQ问题 用于求给定区间内的最大值/最小值问题 ...

  7. 石子合并(四边形不等式优化dp) POJ1160

    该来的总是要来的———————— 经典问题,石子合并. 对于 f[i][j]= min{f[i][k]+f[k+1][j]+w[i][j]} From 黑书 凸四边形不等式:w[a][c]+w[b][ ...

  8. bzoj4177: Mike的农场

    类似于最大权闭合图的思想. #include<cstdio> #include<cstring> #include<iostream> #include<al ...

  9. BZOJ_1624_ [Usaco2008_Open]_Clear_And_Present_Danger_寻宝之路_(最短路_Floyd)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1025 给出\(n\)个点以及之间的边的长度,给出必须访问的点的顺序,求最短路线长度. 分析 用 ...

  10. BZOJ2151: 种树

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2151 题解:此题=数据备份.喜闻乐见挂链表. 代码: #include<cstdio&g ...