Python For Data Analysis-七章第三节

《Python For Data Analysis》的第七章的第三节主要讨论研究的是dataframe数据里的字符串处理方法,内容简单,除了正则,这里就不做阐述来了。

16.1 正则模块re

正则表达式的应用正则表达式常见的应用如下: 1).证字符串,即验证给定的字符串或子字符串是否符合指定特征,譬如验证是否是合法的邮件地址、验证是否为合法的HTTP地址等。 2).找字符串,从给定的文本中查找符合指定特征的字符串,比查找固定字符串更加灵活方便。 3).换字符串,即把给定的字符串中的符合指定特征的子字符串替换为其他字符串,比普通的替换更强大。 4).提取字符串,即从给定的字符串中提取符合指定特征的子字符串。

16.1 正则表达式的测试工具

创建一个正则表达式之后,需要测试该正则表达式是否正确。本书中使用正则表达式测试工具“Notepad++” 来测试正则表达式。操作步骤:打开Notepad++软件,点击"搜索"菜单下的查找,在弹出的对话框的左下角"查找模式"选项里点选"正则表达式",在正上方的输入文本框里输入正则表达式即可搜索匹配字符串了。

16.1.2正则基本概念

  • 正则表达式,正则表达式可以匹配文本片段的模式。正则表达式在程序设计语言中存在着广泛的应用,特别是用来处理字符串。如匹配字符串、查找字符串、替换字符串等。可以说,正则表达式是一段文本或一个公式,它是用来描述用某种模式去匹配一类字符串的公式,并且该公式具有一定的模式。正则表达式就是用某种模式去匹配一类字符串的公式,主要用来描述字符串匹配的工具。正则表达式描述了一种字符串匹配的模式。它可以用来检查字符串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。正则表达式是由普通字符(如字符a到z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。正则表达式就是用于描述某些规则的工具。这些规则经常用于处理字符串中的查找或替换字符串。换句话说,正则表达式就是记录文本规则的代码。正则表达式就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。

  • 匹配,在正则表达式中,匹配是最常用的一个词语,它描述了正则表达式动作结果。给定一段文本或字符串,使用正则表达式从文本或字符串中查找出符合正则表达式的字符串。有可能文本或字符存在不止一个部分满足给定的正则表达式,这时每一个这样的部分被称为一个匹配。

16.2 正则表达式

16.2.1 匹配字符

元字符, 一次只能匹配一个字符或者一个位置。故元字符分:匹配字符的元字符和匹配位置的元字符。

1). 匹配字符的元字符

  • \^{}string 这个正则表达式可以匹配所有以string 字符串开始的行
  • string\$ 这个正则表达式可以匹配所有以string 字符串结尾的行
  • \^{}\$则可以匹配空行
  • \bStr 可以实现匹配以Str开始的单词(等价于\<)
  • Str\b 可以实现匹配以Str结尾的单词(等价于>)

2). 匹配位置的元字符

  • \w可以匹配单词里字符(字母、数字和下划线)
  • \W可以匹配单词里非字符
  • \d可以匹配数字
  • \D可以匹配非数字字符
  • \s可以匹配空格字符
  • \S可以匹配非空格字符

  • 示例:匹配以jea开始

>>> import re
>>> s = 'hello www jeapedu com world'
>>> res = r'\bjea'
>>> print re.findall(res, s)
['jea']
>>> s = 'help jeap jeep jeapedu jeapedu.com '
>>> print re.findall(res, s)
['jea', 'jea', 'jea']
  • 示例:匹配以eap结尾
>>> import re
>>> s = 'help jeap jeep jeapedu jeapedu.com '
>>> res = r'eap\b'
>>> print re.findall(res, s)
['eap']
  • 示例:匹配含hello的行
import re
s = """
ahello
www jeapedu com hellob world

helloc world
nice hellod world
piece of helloe world jeapedu
"""
res = r'\hello'
print 'hello ',re.findall(res, s)

输出结果如下所示:

hello  ['hello', 'hello', 'hello', 'hello', 'hello']
  • 示例:匹配含字母和数字
import re
s = "a1b2c3d"
res = '\w\d'
print re.findall(res, s)
res = '\w\d\w'
print re.findall(res, s)

输出结果如下所示:

['a1', 'b2', 'c3']
['a1b', 'c3d']
  • 示例:示例匹配电话
import re
s = 'telephone to 110-123-114119 or call 4008-6688-9988, 3ks'
res = '\d\d\d\D\d\d\d\D\d\d\d\d\d\d'
print re.findall(res, s)
res = '\d\d\d\d\D\d\d\d\d\D\d\d\d\d'
print re.findall(res, s)

输出结果如下所示:

['110-123-114119']
['4008-6688-9988']

太费劲了!有没有好办法,有!可以直接学习使用限定符来简化这类正则。

16.2.2 字符集合

用方括号括起来的字符集合,如果其中的任何一个字符被匹配,则它就会找到该匹配项,反字符集可在字符前加\^{}

(1).[a-f]匹配a、b、c~f任意某字符,表达式[\^{}b-t] 则能匹配除b 到t 外的任意字符。 字符集也只能匹配一个字符。

(2). 假设想匹配Html网页源文件里的$<$h1$>$$\sim$$<$h7$>$ 字符串,这个匹配正则表达式可以这样去写:$<$h[1234567]$>$或者$<$h[1-7]$>$ 再或者h$\backslash$d。\par

(3). 再举一例,在匹配电子邮件地址时的正则可以这样去写:匹配Email地址的正则表达式:

res = r'[\w\.-]+@[\w\.-]+\.\w{2,4}'

这里,表达式里如果有*表示可以匹配(重复)0次及以上, +表示可以匹配1 次及以上。

import re
s = "Plz write a email to jeap@jeapedu.com or service@jeapedu.com, thanks!"
res = r'\w[\w\.-]+@[\w\.-]+\.\w{2,4}'
print re.findall(res, s)

输出结果如下所示:

['jeap@jeapedu.com', 'service@jeapedu.com']

当然这个正则还是不太准确,不太符合邮件网站对电子邮件名的规定,但能基本匹配出一般字符串里的邮件地址来,也就够用了。

16.2.3 分组或子模式

把一个正则表达式的全部或部分分成一个或多个组。其中,分组使用的字符为“(” 和“)”,即左圆括号和右圆括号。分组之后,可以将字符为“(”和“)”之中的表达式看成一个整体来处理。

例如:P(ython$|$erl)可以匹配Python 或者Perl这个字符串。竖线(替换或者可选)表示分组里可以选择选字符"$|$" 的左边或者右边的规则进行匹配。

再如: (t$|$T)h(e$|$ere$|$eir)可以匹配以下字符串:"the","The","their","Their","there","There"。

import re
s = "www.jeapedu.comwww.JeapedU.comwww.jEAPEDU.comwww.heapedu.comwww.HeapedU.com"
res = '(j|J)\w*(u|U)'
print re.findall(res, s)
res = '[jJ]\w*(u|U)'
print re.findall(res, s)
res = '[jJ]\w*[uU]'
print re.findall(res, s)

输出结果如下所示:

[('j', 'u'), ('J', 'U'), ('j', 'U')]
['u', 'U', 'U']
['jeapedu', 'JeapedU', 'jEAPEDU']

请注意分析分组输出结果,只输出整体匹配括号内的内容。

16.2.4 限定符

正则表达式的元字符一次一般只能匹配一个位置或一个字符,如果要匹配零个或一个或多个字符时,则需要使用限定符。限定符用于指定允许特定字符或字符集自身重复出现的次数。如{n}表示重复n 次、{n,}表示重复至少n 次、{n,m}表示重复至少n 次,最多m 次。常用限定符的说明如下表所示。

  • (pattern)? 问号?重复0次或1次,等同于{0,1}
  • (pattern)* 星号*重复至少0次,等同于{0,}
  • (pattern)+ 加号+重复至少1次,等同于{1,}
  • (pattern)\{m:n\} 重复至少n次,最多m次
  • (pattern)?? 使用零次重复(如有可能)或一次重复
  • (pattern)*? 尽可能少地使用重复的第一个匹配
  • (pattern)+? 尽可能少地使用重复但至少使用一次

例如:"(http://)?(www.)?jeapedu\.com"这样的正则表达式会匹配出以下四个字符串: 'http://www.jeapedu.com','http://jeapedu.com' ,'www.jeapedu.com', 'jeapedu.com'

举例说明,正则表达式'w\{3:4\}.jeapedu.com'能匹配出: 'www.jeapedu.com','wwww.jeapedu.com'。 而正则表达式'colou?r'能匹配colour或者color,

  • 示例:简化的匹配电话正则
import re
s = 'telephone to 110-123-114119 or call 4008-6688-9988, 3ks'
res = '\d+\D\d+\D\d+'
print re.findall(res, s)

输出结果如下所示:

['110-123-114119', '4008-6688-9988']

这里的d可以换成w么?D能换成W么?

16.2.5 通配符

运用于正则表达式里的一些特殊符号,它可以匹配限定长度的字符串,例如点号可以匹配任意一个字符。

16.2.6 转义字符

正则表达式定义了一些特殊的元字符,如\^{}、\$ 和\ .\ 等。由于这些字符在正则表达式中被解释成其他的指定的意义,如果需要匹配这些字符,则需要使用字符转义来解决这一个问题。转义字符为“$\backslash$” (反斜杠),它可以取消这些字符(如\^{}、\$、. 等)在表达式中的具有的特殊意义。

  • $\backslash$b 在正则表达式中,表示单词的边界;如果在字符集中,则表示退格符。
  • $\backslash$t 制表位
  • $\backslash$n、$\backslash$r、$\backslash$f 回车、换行、换页
  • $\backslash$e 回退(Esc)

16.3 Python里使用正则

现在我们已经看了一些简单的正则表达式,那么我们实际在 Python中是如何使用它们的呢? re 模块提供了一个正则表达式引擎的接口,可以让你将正则表达式(字符串)编译(re.compile 函数)成re 模块可以使用、处理的实例对象并用它调用各种函数来进行正则匹配。一旦有了已经编译了的正则表达式的实例对象,就可以实例对象调用match、search、 findall、split 等函数进行正则匹配了。

import re
s = "hello www.jeapedu.com"
print '--------------------------'
res = "[\s\.]"
pat = re.compile(res)
print  pat.findall(s)
print  pat.split(s)
print '--------------------------'
s = "hello www.jeapedu.com"
res = "[\s\.]"
print  re.findall(res, s)
print  re.split(res, s)
print '--------------------------'

运行结果如下所示:

--------------------------
[' ', '.', '.']
['hello', 'www', 'jeapedu', 'com']
--------------------------
[' ', '.', '.']
['hello', 'www', 'jeapedu', 'com']
--------------------------

从结果可以看出不编译res直接用re模块调用findall函数。