python库的学习系列之 7. String Services

 

7.1. string — Common string operations

7.1.1. String constants

string中的常量,string.ascii_lettersstring.ascii_lowercase,string.ascii_uppercasestring.digits,string.hexdigitsstring.letters,string.lowercasestring.octdigits,string.punctuation,string.printablestring.uppercase,

string.whitespace 等。

使用例子: 

  
    
1 >>> import string
2   >>> print string.ascii_letters
3 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
4   >>> print string.whitespace
5
6   >>> print string.hexdigits
7 0123456789abcdefABCDEF

7.1.2. String Formatting

这个主要是从class string.Formatter中提供的一些方法,不是很常用。

7.1.3. Format String Syntax

这个主要是控制了string的输出格式,比较琐碎,具体使用时候可以参考,如左右对齐,占位符等等,见例子:

 

  
    
>>> ' Coordinates: {latitude}, {longitude} ' .format(latitude = ' 37.24N ' , longitude = ' -115.81W ' )
' Coordinates: 37.24N, -115.81W '
>>> coord = { ' latitude ' : ' 37.24N ' , ' longitude ' : ' -115.81W ' }
>>> ' Coordinates: {latitude}, {longitude} ' .format( ** coord)
' Coordinates: 37.24N, -115.81W '

 

7.1.4. Template strings

这是定义string模板的一个用法,比如在数据库查询的时候,可以将查询串的结构首先写好,可以减少重复输入,如:

 

  
    
>>> style = string.Template( ' SELECT [$fld] FROM [$fld] WHERE [$fld] LIKE "1*" AND RIGHT([$fld],1) <> 5 ' )
>>> print style.substitute(fld = ' china ' ,tbl = ' country ' )
SELECT [china] FROM [china] WHERE [china] LIKE
" 1* " AND RIGHT([china], 1 ) <> 5

 

7.1.5. String functions

string.capwords(s[, sep])相当于是一次执行这三个 str.split(), str.capitalize(), str.join()函数的综合运用。见例子:

  
    
>>> str = " i am wangming "
>>> print string.capwords(str)
I Am Wangming

 

string.maketrans(from, to)translate()函数生成一个合适的tablefromto的一一映射。  见例子:

  
    
>>> x = string.maketrans(string.ascii_letters,string.ascii_letters[ 2 :] + string.ascii_letters[: 2 ])
>>> s = ' abc '
>>> string.translate(s,x)
' cde '

 

复杂的例子,见:

  
    
import string
def translator(frm = '' , to = '' , delete = '' , keep = None):
if len(to) == 1 :
to
= to * len(frm)
trans
= string.maketrans(frm, to)
if keep is not None:
allchars
= string.maketrans( '' , '' )
delete
= allchars.translate(allchars, keep.translate(allchars, delete))
def translate(s):
return s.translate(trans, delete)
return translate
# 可以只保留需要的字符
digits_only = translator(keep = string.digits)
digits_only(
' Chris Perkins : 224-7992 ' )
' 2247992 '
# 可以过滤指定的字符:
no_digits = translator(delete = string.digits)
no_digits(‘Chris Perkins :
224 - 7992 ′)
Chris Perkins :
-
# 可以替换指定的字符:
digits_to_hash = translator( from = string.digits, to = ' # ' )
digits_to_hash(‘Chris Perkins :
224 - 7992 ′)
Chris Perkins :
# ##-####’

 

7.1.6. Deprecated string functions

这里面的函数在string and Unicode objects中也被定义了,所以尽量使用那里面的方法。

 

7.2. re — Regular expression operations

讲讲python中的re使用。

7.2.1. Regular Expression Syntax

正则语法过于细节,可以参考python doc http://docs.python.org/library/string.html

7.2.2. Matching vs Searching

python提供了两种基于正则表达式的操作:匹配(match)从字符串的开始检查字符串是否个正则匹配,而搜索(search)检查字符串任意位置是否有匹配的子串(perl默认就是如此)。
注意,即使search的正则以'^'开头,matchsearch也还是有许多不同的。

  
    
>>> re.match( " c " , " abcdef " ) # No match
>>> re.search( " c " , " abcdef " ) # Match
< _sre.SRE_Match object at ... >

 

7.2.3. Module Contents

re.compile(pattern[, flags])把一个正则表达式pattern编译成正则对象,以便可以用正则对象的matchsearch方法。   以下两段内容在语法上是等效的:

  
    
prog = re.compile(pattern)
result
= prog.match(string)
  
    
result = re.match(pattern, string)

 

区别是,用了re.compile以后,正则对象会被cache,这样在需要多次运用这个正则对象的时候,效率会有较大的提升。注意compile中的flags标记:得到的正则对象的行为(也就是模式)可以用flags来指定,值可以由几个下面的值OR得到。

re.I
re.IGNORECASE
让正则表达式忽略大小写,这样一来,[A-Z]也可以匹配小写字母了。此特性和locale无关。

re.L
re.LOCALE
\w\W\b\B\s\S依赖当前的locale

re.M
re.MULTILINE
影响'^''$'的行为,指定了以后,'^'会增加匹配每行的开始(也就是换行符后的位置);'$'会增加匹配每行的结束(也就是换行符前的位置)。

re.S
re.DOTALL
影响'.'的行为,平时'.'匹配除换行符以外的所有字符,指定了本标志以后,也可以匹配换行符。

re.U
re.UNICODE
\w\W\b\B\d\D\s\S依赖Unicode库。

re.X
re.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.search(pattern, string[, flags])扫描string,看是否有个位置可以匹配正则表达式pattern。如果找到了,就返回一个MatchObject的实例,否则返回None,注意这和找到长度为0的子串含义是不一样的。搜索过程受flags的影响。

re.match(pattern, string[, flags])如果字符串string的开头和正则表达式pattern匹配的话,返回一个相应的MatchObject的实例,否则返回None。注意:要在字符串的任意位置搜索的话,需要使用上面的search()

re.split(pattern, string[, maxsplit=0])用匹配pattern的子串来分割string,如果pattern里使用了圆括号,那么被pattern匹配到的串也将作为返回值列表的一部分。如果maxsplit不为0,则最多被分割为maxsplit个子串,剩余部分将整个地被返回。

  
    
>>> re.split( ' \W+ ' , ' Words, words, words. ' )
[
' Words ' , ' words ' , ' words ' , '' ]
>>> re.split( ' (\W+) ' , ' Words, words, words. ' )
[
' Words ' , ' , ' , ' words ' , ' , ' , ' words ' , ' . ' , '' ]
>>> re.split( ' \W+ ' , ' Words, words, words. ' , 1 )
[
' Words ' , ' words, words. ' ]

如果正则有圆括号,并且可以匹配到字符串的开始位置的时候,返回值的第一项,会多出一个空字符串。匹配到字符结尾也是同样的道理:

  
    
>>> re.split( ' (\W+) ' , ' ...words, words... ' )
[
'' , ' ... ' , ' words ' , ' , ' , ' words ' , ' ... ' , '' ]

 

注意,split不会被零长度的正则所分割,例如:

  
    
>>> re.split( ' x* ' , ' foo ' )
[
' foo ' ]
>>> re.split( " (?m)^$ " , " foo\n\nbar\n " )
[
' foo\n\nbar\n ' ]

 

re.findall(pattern, string[, flags])以列表的形式返回string里匹配pattern的不重叠的子串。string会被从左到右依次扫描,返回的列表也是从左到右一次匹配到的。如果pattern里含有的话,那么会返回匹配到的组的列表;如果pattern里有多个组,那么各组会先组成一个元组,然后返回值将是一个元组的列表。 由于这个函数不会涉及到MatchObject之类的概念,所以,对新手来说,应该是最好理解也最容易使用的一个函数了。下面就此来举几个简单的例子:

  
    
>>> re.findall( ' \w+ ' , ' hello, world! ' )
[
' hello ' , ' world ' ]
>>> re.findall( ' (\d+)\.(\d+)\.(\d+)\.(\d+) ' , ' My IP is 192.168.0.2, and your is 192.168.0.3. ' )
[(
' 192 ' , ' 168 ' , ' 0 ' , ' 2 ' ), ( ' 192 ' , ' 168 ' , ' 0 ' , ' 3 ' )]

 

re. finditer(pattern, string[, flags])和上面的findall()类似,但返回的是MatchObject的实例的迭代器。 还是例子说明问题:

  
    
>>> for m in re.finditer( ' \w+ ' , ' hello, world! ' ):
print m.group()

hello
world

 

re.sub(pattern, repl, string[, count])替换,将string里,匹配pattern的部分,用repl替换掉,最多替换count次(剩余的匹配将不做处理),然后返回替换后的字符串。如果string里没有可以匹配pattern的串,将被原封不动地返回。repl可以是一个字符串,也可以是一个函数。如果repl是个字符串,则其中的反斜杆会被处理过,比如 \n 会被转成换行符,反斜杆加数字会被替换成相应的组,比如 \6 表示pattern匹配到的第6个组的内容。 例子:

  
    
>>> re.sub(r ' def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\): ' ,r ' static PyObject*\npy_\1(void)\n{ ' , ' def myfunc(): ' )
' static PyObject*\npy_myfunc(void)\n{ '

 

如果repl是个函数,每次pattern被匹配到的时候,都会被调用一次,传入一个匹配到的MatchObject对象,需要返回一个字符串,在匹配到的位置,就填入返回的字符串。 例子:

  
    
>>> def dashrepl(matchobj):
if matchobj.group(0) == ' - ' : return ' '
else : return ' - '
>>> re.sub( ' -{1,2} ' , dashrepl, ' pro----gram-files ' )
' pro--gram files '

 

零长度的匹配也会被替换,比如:

  
    
>>> re.sub( ' x* ' , ' - ' , ' abcxxd ' )
' -a-b-c-d- '
特殊地,在替换字符串里,如果有 \g 这样的写法,将匹配正则的命名组(前面介绍过的, (?P...) 这样定义出来的东西)。 \g 这样的写法,也是数字的组,也就是说, \g<2> 一般和 \2 是等效的,但是万一你要在 \2 后面紧接着写上字面意义的 0 ,你就不能写成 \20 了(因为这代表第 20 个组),这时候必须写成 \g<2>0 ,另外, \g<0> 代表匹配到的整个子串。   例子:
   
     
>>> re.sub( ' -(\d+)- ' , ' -\g<1>0\g<0> ' , ' a-11-b-22-c ' )
' a-110-11-b-220-22-c '
re.subn(pattern, repl, string[, count])
跟上面的 sub() 函数一样,只是它返回的是一个元组 ( 新字符串 , 匹配到的次数 ) ,还是用例子说话:
   
     
>>> re.subn( ' -(\d+)- ' , ' -\g<1>0\g<0> ' , ' a-11-b-22-c ' )
(
' a-110-11-b-220-22-c ' , 2 )
re.escape(string)
string 中,除了字母和数字以外的字符,都加上反斜杆。
   
     
>>> print re.escape( ' abc123_@#$ ' )
abc123\_\@\
# \$

re. purge ( )Clear the regular expression cache.

exception re.error
如果字符串不能被成功编译成正则表达式或者正则表达式在匹配过程中出错了,都会抛出此异常。但是如果正则表达式没有匹配到任何文本,是不会抛出这个异常的。

7.2.4. Regular Expression Objects

正则对象由re.compile()返回。它有如下的属性和方法。

match(string[, pos[, endpos]])作用和模块的match()函数类似,区别就是后面两个参数。pos是开始搜索的位置,默认为0endpos是搜索的结束位置,如果endpospos还小的话,结果肯定是空的。也就是说只有pos endpos-1 位置的字符串将会被搜索。 例子:

  
    
>>> pattern = re.compile( " o " )
>>> pattern.match( " dog " ) # 开始位置不是o,所以不匹配
>>> pattern.match( " dog " , 1 ) # 第二个字符是o,所以匹配
< _sre.SRE_Match object at 0x011F36E8 >
search (string[, pos[, endpos]]) 作用和模块的 search() 函数类似, pos endpos 参数和上面的 match() 函数类似。

split(string[, maxsplit=0])

findall(string[, pos[, endpos]])

finditer(string[, pos[, endpos]])

sub(repl, string[, count=0])

subn(repl, string[, count=0])
这几个函数,都和模块的相应函数一致。

flags 编译本RE时,指定的标志位,如果未指定任何标志位,则为0

  
    
>>> pattern = re.compile( " o " , re.S | re.U)
>>> pattern.flags
48
groups RE 所含有的组的个数。

groupindex 一个字典,定义了命名组的名字和序号之间的关系。 例子:这个正则有3个组,如果匹配到,第一个叫区号,最后一个叫分机号,中间的那个未命名

  
    
>>> pattern = re.compile( " (?P<quhao>\d+)-(\d+)-(?P<fenjihao>\d+) " )
>>> pattern.groups
3
>>> pattern.groupindex
{
' fenjihao ' : 3 , ' quhao ' : 1 }
pattern   建立本 RE 的原始字符串,相当于源代码了,呵呵。   还是上面这个正则,可以看到,会原样返回:
   
     
>>> print pattern.pattern
(?P
< quhao > \d + ) - (\d + ) - (?P < fenjihao > \d + )

7.2.5. Match Objects

re.MatchObject被用于布尔判断的时候,始终返回True,所以你用 if 语句来判断某个 match() 是否成功是安全的。 它有以下方法和属性:

expand(template)template做为模板,将MatchObject展开,就像sub()里的行为一样,看例子:

  
    
>>> m = re.match( ' a=(\d+) ' , ' a=100 ' )
>>> m.expand( ' above a is \g<1> ' )
' above a is 100 '
>>> m.expand(r ' above a is \1 ' )
' above a is 100 '
group ([group1, ...]) 返回一个或多个子组。如果参数为一个,就返回一个子串;如果参数有多个,就返回多个子串注册的元组。如果不传任何参数,效果和传入一个 0 一样,将返回整个匹配。如果某个 groupN 未匹配到,相应位置会返回 None 。如果某个 groupN 是负数或者大于 group 的总数,则会抛出 IndexError 异常。
   
     
>>> m = re.match(r " (\w+) (\w+) " , " Isaac Newton, physicist " )
>>> m.group(0) # 整个匹配
' Isaac Newton '
>>> m.group( 1 ) # 第一个子串
' Isaac '
>>> m.group( 2 ) # 第二个子串
' Newton '
>>> m.group( 1 , 2 ) # 多个子串组成的元组
( ' Isaac ' , ' Newton ' )

如果有其中有用(?P...)这种语法命名过的子串的话,相应的groupN也可以是名字字符串。例如:

  
    
>>> m = re.match(r " (?P<first_name>\w+) (?P<last_name>\w+) " , " Malcolm Reynolds " )
>>> m.group( ' first_name ' )
' Malcolm '
>>> m.group( ' last_name ' )
' Reynolds '

 

如果某个组被匹配到多次,那么只有最后一次的数据,可以被提取到:

  
    
>>> m = re.match(r " (..)+ " , " a1b2c3 " ) # 匹配到3次
>>> m.group( 1 ) # 返回的是最后一次
' c3 '

 

groups([default])
返回一个由所有匹配到的子串组成的元组。default参数,用于给那些没有匹配到的组做默认值,它的默认值是None ,例如:

  
    
>>> m = re.match(r " (\d+)\.(\d+) " , " 24.1632 " )
>>> m.groups()
(
' 24 ' , ' 1632 ' )
default的作用:
>>> m = re.match(r " (\d+)\.?(\d+)? " , " 24 " )
>>> m.groups() # 第二个默认是None
( ' 24 ' , None)
>>> m.groups( ' 0 ' ) # 现在默认是0了
( ' 24 ' , ' 0 ' )

 

groupdict([default])
返回一个包含所有命名组的名字和子串的字典,default参数,用于给那些没有匹配到的组做默认值,它的默认值是None,例如:

  
    
>>> m = re.match(r " (?P<first_name>\w+) (?P<last_name>\w+) " , " Malcolm Reynolds " )
>>> m.groupdict()
{
' first_name ' : ' Malcolm ' , ' last_name ' : ' Reynolds ' }

 

start([group])
end([group])
返回的是:被组group匹配到的子串在原字符串中的位置。如果不指定groupgroup指定为0,则代表整个匹配。如果group未匹配到,则返回 -1对于指定的mgm.group(g)m.string[m.start(g):m.end(g)]等效。注意:如果group匹配到空字符串,m.start(group)m.end(group)将相等。例如:

  
    
>>> m = re.search( ' b(c?) ' , ' cba ' )
>>> m.start(0)
1
>>> m.end(0)
2
>>> m.start( 1 )
2
>>> m.end( 1 )
2
下面是一个把email地址里的“remove_this”去掉的例子:
>>> email = " tony@tiremove_thisger.net "
>>> m = re.search( " remove_this " , email)
>>> email[:m.start()] + email[m.end():]
' [email protected] '

 

span([group]) 返回一个元组: (m.start(group), m.end(group))

pos 就是传给RE对象的search()match()方法的参数pos,代表RE开始搜索字符串的位置。

endpos 就是传给RE对象的search()match()方法的参数endpos,代表RE搜索字符串的结束位置。

lastindex 最后一次匹配到的组的数字序号,如果没有匹配到,将得到None
例如:(a)b((a)(b))((ab))正则去匹配'ab'的话,得到的lastindex1。而用(a)(b)去匹配'ab'的话,得到的lastindex2

lastgroup 最后一次匹配到的组的名字,如果没有匹配到或者最后的组没有名字,将得到None

re 得到本Match对象的正则表达式对象,也就是执行search()match()的对象。

string  传给search()match()的字符串。

 

7.3. struct — Interpret strings as packed binary data

有了struct,我们就可以很容易操作二进制数据了,比如有一个结构体:

  
    
struct Header
{
unsigned
short id;
char [ 4 ] tag;
unsigned
int version;
unsigned
int count;
}

 

通过socket.recv接收到了一个上面的结构体数据,存在字符串s中,现在需要把它解析出来,可以使用unpack()函数.

  
    
import struct
id, tag, version, count
= struct.unpack( " !H4s2I " , s)

 

上面的格式字符串中,!表示我们要使用网络字节顺序解析,因为我们的数据是从网络中接收到的,在网络上传送的时候它是网络字节顺序的.后面的H表示 一个unsigned shortid,4s表示4字节长的字符串,2I表示有两个unsigned int类型的数据就通过一个unpack,现在id, tag, version, count里已经保存好我们的信息了同样,也可以很方便的把本地数据再packstruct格式

  
    
ss = struct.pack( " !H4s2I " , id, tag, version, count);

 

pack函数就把id, tag, version, count按照指定的格式转换成了结构体Headerss现在是一个字符串(实际上是类似于c结构体的字节流),可以通过 socket.send(ss)把这个字符串发送出去.

7.4. difflib — Helpers for computing deltas

7.5. StringIO — Read and write strings as files

7.6. cStringIO — Faster version of StringIO 

 

7.8. codecs — Codec registry and base classes

因为python内部是使用的unicode来编码的,所以在做字符转码的时候需要用unicode来中间转换一下,其过程如:

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串转换成unicode编码。

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串转换成gb2312编码。

我们会遇到这种情况,当python中间处理非ASCII编码时,经常会出现如下错误:UnicodeDecodeError: 'ascii' codec can't decode byte 0x?? in position 1: ordinal not in range(128)

  
    
import sys
reload(sys)
sys.setdefaultencoding(
' gb2312 ' ),相应的也有get的方法

或者在开头加上

  
    
# coding=gbk

来制定字符编码格式就可以避免这个问题了。

 

例子二

  
    
1 # coding=gbk
2 import codecs
3
4 f = codecs.open( ' c:/intimate.txt ' , ' a ' , ' utf-8 ' )说明文件时UTF - 8编码
5 f.write(u ' 中文 ' )
6 s = ' 中文 '
7 f.write(s.decode( ' gbk ' ))用gbk去编码这个字符串,并写到文件里
8 f.close()
9
10 f = codecs.open( ' c:/intimate.txt ' , ' r ' , ' utf-8 ' )用utf - 8形式打开这个文件
11 s = f.readlines()
12 f.close()
13 for line in s:
14 print line.encode( ' gbk ' )用gbk去解码这个字符串并输出

 

codecs模块中重要的函数之一是lookup,它只有一个参数encoding,指的是编码方式的名称,即utf-8或者gb2312等等。如下示例:

  
    
>>> import codecs
>>> t = codecs.lookup( " utf-8 " )

 

lookup函数返回一个包含四个元素的TUPLE 其中t[0]encoder的函数引用,t[1]decoder的函数引用,t[2] UTF-8编码方式的StreamReader类对象引用,t[3]UTF-8编码方式的 

你可能感兴趣的:(service)