python cookbook第二章笔记

2.1 使用多个界定符分割字符串

你需要将一个字符串分割成多个字段,但是分隔符(还有周围的空格)并不是固定的

string 对象的 split() 方法只适应于非常简单的字符串分割情形, 它并不允许有多个分隔符或者是分隔符周围不确定的空格。 当你需要更加灵活的切割字符串的时候,最好使用 re.split() 方法:

>>> line = 'asdf fjdk; afed, fjek,asdf, foo'
>>> import re
>>> re.split(r'[;,\s]\s*', line)
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

函数 re.split() 是非常实用的,因为它允许你为分隔符指定多个正则模式。 比如,在上面的例子中,分隔符可以是逗号,分号或者是空格,并且后面紧跟着任意个的空格。 只要这个模式被找到,那么匹配的分隔符两边的实体都会被当成是结果中的元素返回。 返回结果为一个字段列表,这个跟 str.split() 返回值类型是一样的。

当你使用 re.split() 函数时候,需要特别注意的是正则表达式中是否包含一个括号捕获分组。 如果使用了捕获分组,那么被匹配的文本也将出现在结果列表中。

2.2 字符串开头或结尾匹配

你需要通过指定的文本模式去检查字符串的开头或结尾,比如文件后缀,URL Scheme等等。

检查字符串开头或结尾的一个简单方法是使用 str.startswith() 或者是 str.endswith() 方法。

如果你想检查多种匹配可能,只需要将所有的匹配项放入到一个元组中去, 然后传给 startswith() 或者 endswith() 方法:

>>> import os
>>> filenames = os.listdir('.')
>>> filenames
[ 'Makefile', 'foo.c', 'bar.py', 'spam.c', 'spam.h' ]
>>> [name for name in filenames if name.endswith(('.c', '.h')) ]
['foo.c', 'spam.c', 'spam.h'
>>> any(name.endswith('.py') for name in filenames)
True
>>>

2.3 用Shell通配符匹配字符串

你想使用 Unix Shell 中常用的通配符(比如 .py , Dat[0-9].csv 等)去匹配文本字符串。

fnmatch 模块提供了两个函数—— fnmatch() 和 fnmatchcase() ,可以用来实现这样的匹配。用法如下:

>>> from fnmatch import fnmatch, fnmatchcase
>>> fnmatch('foo.txt', '*.txt')
True
>>> fnmatch('foo.txt', '?oo.txt')
True
>>> fnmatch('Dat45.csv', 'Dat[0-9]*')
True
>>> names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']
>>> [name for name in names if fnmatch(name, 'Dat*.csv')]
['Dat1.csv', 'Dat2.csv']
>>>

fnmatch() 函数匹配能力介于简单的字符串方法和强大的正则表达式之间。 如果在数据处理操作中只需要简单的通配符就能完成的时候,这通常是一个比较合理的方案。

2.4 字符串匹配和搜索

你想匹配或者搜索特定模式的文本

如果你想匹配的是字面字符串,那么你通常只需要调用基本字符串方法就行, 比如 str.find() , str.endswith() , str.startswith() 或者类似的方法

对于复杂的匹配需要使用正则表达式和 re 模块。

如果你想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对象。

match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位置, 使用 findall() 方法去代替。

findall() 方法会搜索文本并以列表形式返回所有的匹配。 如果你想以迭代方式返回匹配,可以使用 finditer() 方法来代替,

使用re模块进行匹配和搜索文本的最基本方法。 核心步骤就是先使用 re.compile() 编译正则表达式字符串, 然后使用 match() , findall() 或者 finditer() 等方法。

当写正则式字符串的时候,相对普遍的做法是使用原始字符串比如 r'(\d+)/(\d+)/(\d+)' 。 这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。 如果不这样做的话,你必须使用两个反斜杠,类似 '(\d+)/(\d+)/(\d+)' 。

2.5 字符串搜索和替换

你想在字符串中搜索和匹配指定的文本模式

对于简单的字面模式,直接使用 str.replace() 方法即可
对于复杂的模式,请使用 re 模块中的 sub() 函数。sub() 函数中的第一个参数是被匹配的模式,第二个参数是替换模式

如果你打算用相同的模式做多次替换,考虑先编译它来提升性能。对于更加复杂的替换,可以传递一个替换回调函数来代替。

2.6 字符串忽略大小写的搜索替换

你需要以忽略大小写的方式搜索与替换文本字符串

为了在文本操作时忽略大小写,你需要在使用 re 模块的时候给这些操作提供 re.IGNORECASE 标志参数。

2.7 最短匹配模式

你正在试着用正则表达式匹配某个文本模式,但是它找到的是模式的最长可能匹配。 而你想修改它变成查找最短的可能匹配。

为了修正这个问题,可以在模式中的*操作符后面加上?修饰符,这样就使得匹配变成非贪婪模式,从而得到最短的匹配,也就是我们想要的结果。

2.8 多行匹配模式

你正在试着使用正则表达式去匹配一大块的文本,而你需要跨越多行去匹配。

这个问题很典型的出现在当你用点(.)去匹配任意字符的时候,忘记了点(.)不能匹配换行符的事实。 为了修正这个问题,你可以修改模式字符串,增加对换行的支持。

2.9 将Unicode文本标准化

你正在处理Unicode字符串,需要确保所有字符串在底层有相同的表示。

在需要比较字符串的程序中使用字符的多种表示会产生问题。 为了修正这个问题,你可以使用unicodedata模块先将文本标准化:

>>> import unicodedata
>>> t1 = unicodedata.normalize('NFC', s1)
>>> t2 = unicodedata.normalize('NFC', s2)
>>> t1 == t2
True
>>> print(ascii(t1))
'Spicy Jalape\xf1o'
>>> t3 = unicodedata.normalize('NFD', s1)
>>> t4 = unicodedata.normalize('NFD', s2)
>>> t3 == t4
True
>>> print(ascii(t3))
'Spicy Jalapen\u0303o'
>>>

normalize() 第一个参数指定字符串标准化的方式。 NFC表示字符应该是整体组成(比如可能的话就使用单一编码),而NFD表示字符应该分解为多个组合字符表示。

2.10 在正则式中使用Unicode

你正在使用正则表达式处理文本,但是关注的是Unicode字符处理。

默认情况下 re 模块已经对一些Unicode字符类有了基本的支持。 比如, \d 已经匹配任意的unicode数字字符了
如果你想在模式中包含指定的Unicode字符,你可以使用Unicode字符对应的转义序列(比如 \uFFF 或者 \UFFFFFFF )。
当执行匹配和搜索操作的时候,最好是先标准化并且清理所有文本为标准化格式

2.11 删除字符串中不需要的字符

你想去掉文本字符串开头,结尾或者中间不想要的字符,比如空白。

strip() 方法能用于删除开始或结尾的字符。 lstrip() 和 rstrip() 分别从左和从右执行删除操作。 默认情况下,这些方法会去除空白字符,但是你也可以指定其他字符。
但是需要注意的是去除操作不会对字符串的中间的文本产生任何影响。
如果你想处理中间的空格,那么你需要求助其他技术。比如使用 replace() 方法或者是用正则表达式替换。

2.12 审查清理文本字符串

一些无聊的幼稚黑客在你的网站页面表单中输入文本”pýtĥöñ”,然后你想将这些字符清理掉。

文本清理问题会涉及到包括文本解析与数据处理等一系列问题。 在非常简单的情形下,你可能会选择使用字符串函数(比如 str.upper() 和 str.lower() )将文本转为标准格式。 使用 str.replace() 或者 re.sub() 的简单替换操作能删除或者改变指定的字符序列。

2.13 字符串对齐

你想通过某种对齐方式来格式化字符串

对于基本的字符串对齐操作,可以使用字符串的 ljust() , rjust() 和 center() 方法。
函数 format() 同样可以用来很容易的对齐字符串。 你要做的就是使用 <,> 或者 ^ 字符后面紧跟一个指定的宽度。
format() 函数的一个好处是它不仅适用于字符串。它可以用来格式化任何值,使得它非常的通用。 比如,你可以用它来格式化数字

2.14 合并拼接字符串

你想将几个小的字符串合并为一个大的字符串

如果你想要合并的字符串是在一个序列或者 iterable 中,那么最快的方式就是使用 join() 方法。比如:

>>> parts = ['Is', 'Chicago', 'Not', 'Chicago?']
>>> ' '.join(parts)
'Is Chicago Not Chicago?'
>>> ','.join(parts)
'Is,Chicago,Not,Chicago?'
>>> ''.join(parts)
'IsChicagoNotChicago?'
>>>

如果你仅仅只是合并少数几个字符串,使用加号(+)通常已经足够了

最重要的需要引起注意的是,当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的, 因为加号连接会引起内存复制以及垃圾回收操作。 这种写法会比使用 join() 方法运行的要慢一些,因为每一次执行+=操作的时候会创建一个新的字符串对象。 你最好是先收集所有的字符串片段然后再将它们连接起来。

2.15 字符串中插入变量

你想创建一个内嵌变量的字符串,变量被它的值所表示的字符串替换掉

多年以来由于Python缺乏对变量替换的内置支持而导致了各种不同的解决方案。 作为本节中展示的一个可能的解决方案,你可以有时候会看到像下面这样的字符串格式化代码:

>>> name = 'Guido'
>>> n = 37
>>> '%(name) has %(n) messages.' % vars()
'Guido has 37 messages.'
>>>

你可能还会看到字符串模板的使用:

>>> import string
>>> s = string.Template('$name has $n messages.')
>>> s.substitute(vars())
'Guido has 37 messages.'
>>>

然而, format() 和 format_map() 相比较上面这些方案而已更加先进,因此应该被优先选择。 使用 format() 方法还有一个好处就是你可以获得对字符串格式化的所有支持(对齐,填充,数字格式化等待), 而这些特性是使用像模板字符串之类的方案不可能获得的。

2.16 以指定列宽格式化字符串

你有一些长字符串,想以指定的列宽将它们重新格式化。

textwrap 模块对于字符串打印是非常有用的,特别是当你希望输出自动匹配终端大小的时候。 你可以使用 os.get_terminal_size() 方法来获取终端的大小尺寸。比如:

>>> import os
>>> os.get_terminal_size().columns
80
>>>

fill() 方法接受一些其他可选参数来控制tab,语句结尾等。

2.17 在字符串中处理html和xml

你想将HTML或者XML实体如 &entity; 或 &#code; 替换为对应的文本。 再者,你需要转换文本中特定的字符(比如<, >, 或 &)。

如果你想替换文本字符串中的 ‘<’ 或者 ‘>’ ,使用 html.escape() 函数可以很容易的完成。
如果你正在处理的是ASCII文本,并且想将非ASCII文本对应的编码实体嵌入进去, 可以给某些I/O函数传递参数 errors='xmlcharrefreplace' 来达到这个目。

2.18 字符串令牌解析

你有一个字符串,想从左至右将其解析为一个令牌流。

你可能感兴趣的:(python cookbook第二章笔记)