第二章:字符串和文本

1.针对任意多的分隔符拆分字符串

问题:我们需要将字符串拆分为不同的字段,但是分隔符(以及分隔符之间的空格)在整个字符串中并不一致

解答:字符串对象的split()方法只能处理非常简单的情况,而且不支持多个分隔符,对分隔符周围可能存在的空格也无能为力。但是可以使用re.split()

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

2.在字符串的开头或者结尾处做文本匹配

问题:我们需要在字符串的开头或者结尾处按照指定的文本模式做检查,例如检查文件的扩展名、url协议类型等;

解决方案:有一种简单的方法来检查字符串的开头或者结尾:
startswith() 和 endswith()
如果是做列表的字符串检查并筛选的话,可以配套列表推导式;

if any(name.endswith(('.c','.h')) for name in listdir(dirname)):

3.利用shell通配符做字符串匹配

4.文本模式的匹配和查找

如果想要匹配的只是简单的文字,那么通常只需要用基本的字符串方法就可以了,比如:str.find(), str.endswith(),str.startswith()或类似的函数;

>>>text = 'year, but no,but yeah,but bo,but yeah'
>>>text.startswith('yeah')        #True
>>>text.endswith('no')             #False
>>>text.find('no')                       #10

对于更为复杂的匹配则需要用到正则表达式以及RE模块:

>>>text1 = '11/27/2017'
>>>import re 
>>> if re.match(r'\d+/\d+/\d+',text):
 >>>  print('yes')

match()方法总是尝试在字符串的开头找到匹配项,如果想针对真个文本搜索出所有的匹配项,那么应该使用findall()方法;
findall()方法搜索整个文本并找出所有的匹配项然后将他们以列表的形式返回,如果想以迭代的方式找出匹配项,可以使用finditer()方法;

>>>text = 'Today is 11/27/2017. pcCon starts 3/13/2015'
>>>datepat = re.compile(r'\d+/\d+/\d+')
>>>datepat.findall(text)

当定义正则表达式的时候,我们经常会将部分模式用括号包起来的方式引入捕获组,
datapat = re.compile(r'(\d+)/(\d+)/(\d+)')

捕获组通常能简化后续对匹配结果的处理,因为每个组的内容都可以单独提取出来;

5.查找和替换文本

问题:我们想对字符串的文本做查找和替换

解决方案:对于简单的文本模式,使用str.replace()即可;

>>>text = 'Today is 11/27/2017. pcCon starts 3/13/2015'
>>>text.replace('yeah','yep')

针对更加复杂的模式,可以使用re模块中的sub()函数方法。为了说明如何使用,假设我们想把日期格式从“11/27/2017”改写为“2017-11-27”:

>>>text = 'Today is 11/27/2017. pcCon starts 3/13/2015'
>>>re.sub(r'(\d+)/(\d+)/(\d+)',r'\3-\1-\2',text)

sub()的第一个参数是要匹配的模式,第二个参数是要替换上的模式。类似“\3”这样的反斜线加数字的符号代表着模式中捕获组的数量;
如果打算用相同的模式执行重复的替换,可以考虑先将模式编译以获取更好的性能;

>>>import re
>>>datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>>datepat.sub(r'\3-\1-\2',text)
'Today is 2017-11-27.pcCon starts 2015-3-13'

除了得到替换后的文本外,如果还想知道一共完成了多少次替换,可以使用re.subn().

>>>newtext ,n = datepat.subn(r'\3-\1-\2',text)
>>>newtext
'Today is 2017-11-27.pcCon starts 2015-3-13'
>>>n
2

6.以不区分大小写的方式对文本做查找和替换

问题:我们需要以不区分大小写的方式在文本中进行查找,可能还需要做替换

解决方案:要进行不区分大小写的文本操作,我们需要使用re模块并且对各种操作都要加上re.IGNORECASE标记;

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

7.定义实现最短匹配的正则表达式

问题:我们正在尝试用正则表达式对文本模式做匹配,单识别出来的是最长的可能匹配,相反,我们想将其修改为找出最短的可能匹配;

解决方案:模式:r'(.)'尝试去匹配将包含在引号中的文本,但是,操作符在正则表达式中时贪心策略,所以匹配过程是基于找出最长的可能匹配来进行的。要解决这个问题,只要在模式中的操作符后面加上?修饰符就可以了; ==> r'(.?)'

8.编写多行模式的正则表达式

9.将Unicode文本统一为规范形式

10.用正则表达式处理Unicode字符;

11.从字符串中去掉不需要的字符

问题:我们想在字符串的开始,结尾或者中间去掉不需要的字符,比如说空格符;

解决方案:strip()方法可以用来充字符串开始或者结尾处去掉字符,lstrip()和rstrip()分别充左边、右边开始执行去掉字符的操作。默认情况下这些方法去掉的是空格符,但也可以指定字符;

>>>str.strip()    #默认情况下去掉空格符
>>>str.strip('/')  #去掉指定的字符

上面的操作只能去掉字符串开始或者结尾处的字符,但是对于字符串中间的指定字符并不起作用;如果想要对里面的空格执行某些操作,应该使用其他技巧,比如正则表达式或者replace()方法;

>>>s.replace(' ' ,'')
>>>re.sub('\s+','',s)

12.文本过滤和清理

13.对其文本字符串

问题:我们需要以某种对齐方式将文本做格式化处理

解决方案:对于基本的字符串对齐的要求,可以使用字符串的ljust(),rjust()和center()方法,

>>> text = 'Hello world'
>>> text.ljust(2)
'Hello world'
>>> text.ljust(20)
'Hello world         '
>>> text.rjust(20)
'         Hello world'
>>> text.center(20)
'    Hello world     '
>>> text.rjust(20,'=')
'=========Hello world'
>>> text.ljust(20,'=')
'Hello world========='
>>> text.center(20,'=')
'====Hello world====='
>>>

format()函数也可以用来轻松的完成对齐任务。需要做的就是合理的利用‘>’、‘<’或者‘^’字符串以及一个期望的宽度值

>>> format(text,'>20')
'         Hello world'
>>> format(text,'<20')
'Hello world         '
>>> format(text,'^20')
'    Hello world
>>> format(text,'*^20')
'****Hello world*****'
>>> format(text,'*<20')
'Hello world*********'

14.字符串链接和合并

问题:我们想将很多小字符串合并成一个大的字符串;

解决方案:如果想要合并的字符串在一个序列或者可迭代对象中,那么将他们合并起来的最快方式是使用join()方法;

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

对于简单的几个字符串的连接可以直接使用“+”操作符;

>>> a = 'Is Chicago'
>>> b = 'Not Chicago?'
>>> a + ' ' + b
'Is Chicago Not Chicago?'

针对更加负责的字符串格式操作,+操作符同样可以作为format()的替代,

>>> print('{} {}'.format(a,b))
Is Chicago Not Chicago?

对于列表中的格式不统一的时候;我们需要处理后才能join()

>>> data = ['ACME',50,91.1]
>>> ','.join(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 1: expected str instance, int found
>>> ','.join(str(d) for d in data)
'ACME,50,91.1'

15.给字符串中的变量名做插值处理

问题:想创建一个字符串,其中嵌入的变量名会以变量的字符串值形式替换掉;

解决方案:Python并不支持在字符串中对变量做简单的值替换,但是,这个功能可以通过字符串的format()方法近似的模拟出来;

>>> s = '{name} has {n} messages.'
>>> s.format(name='overad',n=37)
'overad has 37 messages.'

两一种方式:如果要替换的值确实能在变量中找到,则可以将format_map()和vars()联合起来使用,示例如下:

>>> name = 'overad'
>>> n = 33
>>> s.format_map(vars())
'overad has 33 messages.'

上面的两种方法都无法优雅的处理缺少某个值的情况;避免出现这种情况的一种方法就是单独定义一个带有missing()方法的类,

>>> class safesub(dict):
...     def __missing__(self,key):
...             return '{' + key + '}'
...
>>> del n
>>> s.format_map(safesub(vars()))
'overad has {n} messages.'

如果发现自己在代码中常常需要执行这些步骤,则可以将替换变量的过程隐藏在一个小型的功能函数内;

>>> import sys
>>> def sub(text):
...     return text.format_map(safesub(sys._getframe(1).f_locals))
...
>>> name = 'overad'
>>> n = 37
>>> print(sub('Hello {name}'))
Hello overad
>>> print(sub('You have {n} messages.'))
You have 37 messages.
>>> print('You favourite color is {color}')
You favourite color is {color}

16.以固定的列数重新格式化文本

问题:我们有一些很长的字符串,想将他们重新格式化,使得他们能按照用户指定的列数来显示;

解决方案:可以使用textwrap模块来重新格式化文本的输出;

>>>import textwrap
>>>print(textwrap.fill(s,70))

textwrap 模块能够以简单直接的方式对文本格式做整理使其适合于答应--尤其是当希望输出结果能很好地显示在终端上时;关于终端的尺寸大小,可以通过os.get_terminal_size()来获取;

>>> import os
>>> os.get_terminal_size()
os.terminal_size(columns=105, lines=28)

17.在文本中处理HTML和XML实体

18.文本分词

19.编写一个简单的递归下降解析器

20.在字符串上执行文本操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351