第二章:字符串与文本

文章目录

第一节:字符串操作

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

使用split() 拆分字符串

例:

aString = "vnein,fslf,lfejf,nldsl,sjpa"
print(aString.split(','))      #['vnein', 'fslf', 'lfejf', 'nldsl', 'sjpa']

【注意】 string 对象的 split() 方法只适应于非常简单的字符串分割情形’’’

使用正则 re.split() 拆分字符串

例:

astring = 'asdf fjdk; afed, fjek,asdf, foo'

import re

print(re.split(r'[;,\s]\s*',astring))   
#['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

匹配字符串开头或结尾

使用 startswith() / endswith()匹配

例:

'''最简单容易的匹配'''

filename = 'what_the_fuck.txt'
print(filename.startswith('what'))  #True
print(filename.endswith('txt'))     #True

url = 'http://www.baidu.com'
print(url.startswith('http:'))      #True


''' 如果想检查多种匹配可能,只需要将所有的匹配项放入到一个元组中去,记住,是元组'''
#例:匹配列表中的py文件
mlist = [
    'one.txt',
    'two.jpg',
    'three.txt',
    'four.py',
    'five.py',     
    'six.jpg',
    'seven.txt'
]
print([file for file in mlist if file.endswith(('txt','py'))])
#['one.txt', 'three.txt', 'four.py', 'five.py', 'seven.txt']
使用切片匹配

例:

'''切片实现'''  

filename = 'what_the_fuck.txt' 
print(filename[:4]=='what')    #True 
print(filename[-4:]=='.txt')   #True
使用正则匹配

例:

import re

url = 'http://www.python.org' 
print(re.match('http:|https:|ftp:', url)) 
#<_sre.SRE_Match object; span=(0, 5), match='http:'>

用 Shell 通配符匹配字符串

使用 fnmatch() 匹配字符串

例:

from fnmatch import fnmatch
 
#配匹字符串
print(fnmatch('foo.txt', '*.txt')) #True
print(fnmatch('foo.txt', '?oo.txt')) #True 
print(fnmatch('Dat45.csv', 'Dat[0-9]*')) #True

#列表也能轻而易举地用fnmatch()匹配
names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py'] 
print([name for name in names if fnmatch(name, 'Dat*.csv')]) 
#['Dat1.csv', 'Dat2.csv']  

fnmatch() 函数使用底层操作系统的大小写敏感规则 (不同的系统是不一样的)来匹配模式。

#在OS X (Mac) 中会要求大小写统一
print(fnmatch('foo.txt', '*.TXT'))  #False

#而在windows中,则忽略大小写
print(fnmatch('foo.txt', '*.TXT'))  #True
使用 fnmatchcase() 匹配字符串

此方法与上面方法一样,只是完全不必考虑底层系统对大小写敏感的问题,

例:

from fnmatch import fnmatchcase
print(fnmatchcase('foo.txt', '*.TXT'))  #False

字符串匹配和搜索

普通匹配法

str.find() —— 找查位置
str.endswith() —— 匹配结尾
str.startswith() —— 匹配开头

例:

text = 'yeah, but no, but yeah, but no, but yeah'

print(text == 'yeah')   #False
print(text.startswith('yeah'))   #True
print(text.endswith('no'))     #False
print(text.find('no'))   #10
使用正则 + re.match() / re.findall() 匹配

例:想匹配数字格式的日期字符串比如 11/27/2012

text1 = '11/27/2012'
text2 = 'Nov 27, 2012'

import re

if re.match(r'\d+/\d+/\d+', text1):
    print('yes')
else:
    print('no')    #yes

if re.match(r'\d+/\d+/\d+', text2):
    print('yes')
else:
    print('no')    #no

当然,如果正则要多次使用的话,也可以进行预编绎
例:

#先进行预编绎
datepat = re.compile(r'\d+/\d+/\d+')

if datepat.match(text1):
    print('yes')
else:
    print('no')    #yes

if datepat.match(text2):
    print('yes')
else:
    print('no')    #no

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

例:

text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
print(datepat.findall(text))      #['11/27/2012', '3/13/2013']

字符串搜索和替换

使用 str.repalce() 替换字符串

对于简单的字面模式,直接使用 str.repalce() 方法即可

例:

text = 'yeah, but no, but yeah, but no, but yeah'
print(text.replace('yeah', 'fuck'))
# 'fuck, but no, but fuck, but no, but fuck'
使用 re.sub() 替换字符串

对于复杂的模式,请使用 re 模块中的 sub() 函数进行替换。比如想将 11/27/201 的日期字符串改成 2012-11-27 。

例:

text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'

import re
print(re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text))
#'Today is 2012-11-27. PyCon starts 2013-3-13.'

对于更加复杂的模式,就要使用回调函数来代替了

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

使用正则并添加 re.IGNORECASE

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

例:

text = 'UPPER PYTHON, lower python, Mixed Python'

#搜索
print(re.findall('python', text, flags=re.IGNORECASE))
#['PYTHON', 'python', 'Python']

#替换
print(re.sub('python', 'snake', text, flags=re.IGNORECASE))
# 'UPPER snake, lower snake, Mixed snake'

####非贪婪模式匹配字符串

使用 “ ?”

例:

import re

#定义正则,匹配引号内的内容
rul = re.compile(r'\"(.*)\"')

#完美匹配
text1 = '贫僧法号 "不懂"'
print(rul.findall(text1))   #['不懂']

#不完整匹配
text2 = '贫僧法号 "不懂" .贫道法号 "不问"'
print(rul.findall(text2))   #['不懂" .贫道法号 "不问']

在正则表达式中 * 操作符是贪婪的,因此匹配操作会查找最长的可能匹配。于是在第二个例子中搜索 text2 的时候返回结果并不是我们想要的。此时需要使用非贪婪模式:“?”

例:

#定义非贪婪的正则
str_pat = re.compile(r'\"(.*?)\"')
print(str_pat.findall(text2))    #['不懂', '不问']

多行匹配模式匹配字符串

使用 (?:.|\n)

例:

import re

#定义正则
rul = re.compile(r'/\*(.*?)\*/')

text1 = '/* 这是一句话 */'
text2 = '''
    /* 这是一句话,
    但是还有第二句,
    另外还有第三句   */
'''
#完美匹配
print(rul.findall(text1))   # [' 这是一句话 ']
#不完美匹配
print(rul.findall(text2))   # []

当用点 (.) 去匹配任意字符的时候,忘记了点 (.) 不能匹配换行符的事实。匹配不到多行内容。这时需修改模式字符串,增加对换行的支持

例:

#正则添加(?:.|\n)
rul2 = re.compile(r'/\*((?:.|\n)*?)\*/')
#完美匹配
print(rul2.findall(text2))   #['这是一句话,\n 但是还有第二句,\n 另外还有第三句']
使用标志参数 re.DOTALL

re.compile() 函数接受一个标志参数叫 re.DOTALL ,它也可以让正则表达式中的点 (.) 匹配包括换行符在内的任意字符。

例:

#使用re.compile()
rul3 = re.compile(r'/\*(.*?)\*/', re.DOTALL)
#完美匹配
print(rul3.findall(text2))   #[' 这是一句话,\n 但是还有第二句,\n 另外还有第三句   ']

第二节:文本操作

将 Unicode 文本标准化

使用整体字符和组合字符

例:

#这里有两个文本
s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'

print(s1)         #'Spicy Jalapeño'
print(s2)         #'Spicy Jalapeño'
print(s1 == s2)   #False
print(len(s1))    #14
print(len(s2))    #15

‘’‘打印出来虽然相同,但却是两个不同形式的东西,第一种使用整体字符”ñ”(U+00F1),第二种使用拉丁字母”n” 后面跟一个”˜” 的组合字符 (U+0303)。’’’
在需要比较字符串的程序中使用字符的多种表示往往会产生问题。

使用 unicodedata.normalize()

例:

import unicodedata

s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'

#使用整体组成的标准化方式NFC
t1 = unicodedata.normalize('NFC', s1)
t2 = unicodedata.normalize('NFC', s2)
print(t1 == t2)      #True
print(ascii(t1))     #'Spicy Jalape\xf1o'

#使用多组合的标准化方式NFD
t3 = unicodedata.normalize('NFD', s1)
t4 = unicodedata.normalize('NFD', s2)
print(t3 == t4)     #True
print(ascii(t3))    #'Spicy Jalapen\u0303o'>

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

正则中使用 Unicode

默认情况下 re 模块已经对一些 Unicode 字符类有了基本的支持。比如,\d 已经匹配任意的 unicode 数字字符

例:

import re
num = re.compile('\d+') 

print(num.match('123'))      #<_sre.SRE_Match object; span=(0, 3), match='123'>
print(num.match('\u0661\u0662\u0663'))     #<_sre.SRE_Match object; span=(0, 3), match='١٢٣'>

如果想在模式中包含指定的 Unicode 字符,你可以使用 Unicode 字符对应的转义序列 (比如 \uFFF 或者 \UFFFFFFF )。比如,下面是一个匹配几个不同阿拉伯编码页面中所有字符的正则表达式:

例:

arabic = re.compile('[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff]+')

当执行匹配和搜索操作的时候,最好是先文本标准化并且清理所有文本为标准化格式。但是同样也应该注意一些特殊情况,比如在忽略大小写匹配和大小写转换时的行为

例:

import re

pat = re.compile('stra\u00dfe', re.IGNORECASE)
s = 'straße'
print(pat.match(s))   # <_sre.SRE_Match object; span=(0, 6), match='straße'>

print(pat.match(s.upper()))    # None
print(s.upper())    # STRASSE

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

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

使用 strip()删除头尾空白字符

例:

#使用strip()删除开始和结尾的空格符
s = ' hello world \n'
print(s.strip())       # hello world
使用 lstrip() 和 rstrip()定义删除头或尾字符

lstrip() 和 rstrip() 分别是从左和从右执行删除操作。默认情况下,这些方法会去除空格符,但是也可以指定其他字符。

例:

s = '  fuck you    \n'
#删除左边的空格
print(s.lstrip())    # 'fuck you    '
#删除右边的空格
print(s.rstrip())    #'  fuck you'

t = '-----hello====='
#自定义删除左边的‘-’
print(t.lstrip('-'))    # 'hello====='
#删除两边的‘-=’
print(t.strip('-='))    # 'hello'
使用 replace() 删除中间字符

去除操作不会对字符串的中间的空格符产生任何影响。想去除中间的空格,就要用到 replace()

例:

s = 'are you talking to me?'
print(s.replace(' ', ''))     # areyoutalkingtome?
使用正则 re 删中间空格字符

例:

s = 'are you talking to me?'

import re
print(re.sub('\s+', '', s))  # areyoutalkingtome?

清理文本字符串

有时用户会输入一些无聊的字符串,如:pýtĥöñ
文本清理问题会涉及到包括文本解析与数据处理等一系列问题。在非常简单的情形
下,我们可能会选择使用字符串函数 (比如 str.upper() 和 str.lower() ) 将文本转为标
准格式。使用 str.replace() 或者 re.sub() 的简单替换操作能删除或者改变指定的
字符序列。我们同样还可以使用 unicodedata.normalize() 函数将 unicode文本标准化。
然后,有时候我们可能还想在清理操作上更进一步。比如,想消除整个区间上
的字符或者去除变音符。为了这样做,我们可以使用经常会被忽视的 str.translate()
方法。

例:

s = 'pýtĥöñ\fis\tawesome\r\n'
print(s)   #  pýtĥöñis	awesome

#清理第一步:替换(把另一奇怪的字符先换成空格符)
p = {
    ord('\t') : ' ',
    ord('\f') : ' ',
    ord('\r') : None # Deleted
}
afterTranslate = s.translate(p)
print(afterTranslate)    # pýtĥöñ is awesome

#第二步,分解形式字符。
import unicodedata

#使用多组合的标准化方式NFD,分离出和音符
b = unicodedata.normalize('NFD', afterTranslate)
print(b)   #pýtĥöñ is awesome

#第三步,删除和音符
'''方法一'''
print(b.encode('ascii', 'ignore').decode('ascii'))  # python is awesome

'''方法二'''
import sys

#使用 dict.fromkeys() 方法构造一个字典,每个 Unicode 和音符作为键,对于的值全部为 None
Nonedict = dict.fromkeys(c for c in range(sys.maxunicode)if unicodedata.combining(chr(c)))
#调用 translate 函数删除所有重音符。
print(b.translate(Nonedict))   # python is awesome

第三步方法一涉及到 I/O 解码与编码函数。这里的思路是先对文本做一些初步的清理,然后再结合 encode() 或者 decode() 操作来清除或修改它。
而方法二中,通过使用 dict.fromkeys() 方法构造一个字典,每个 Unicode 和音符作为键,对于的值全部为 None 。然后使用 unicodedata.normalize() 将原始输入标准化为分解形式字符。然后再调用 translate 函数删除所有重音符。

字符串对齐

使用 ljust() , rjust() 和 center() 格式化字符串

例:

text = 'Hello World'

#左对齐、右对齐、居中
print(text.ljust(20))    # "Hello World         "
print(text.rjust(20))    # "         Hello World"
print(text.center(20))   # "    Hello World     "

#所有这些方法都能接受一个可选的填充字符
print(text.rjust(20,'='))    # '=========Hello World'
print(text.center(20,'*'))   # '****Hello World*****'
使用 format() 格式化字符串/数字

函数 format() 同样可以用来很容易的对齐字符串。你要做的就是使用 【<】,【>】 或者【ˆ】 字符后面紧跟一个指定的宽度。

例:

text = 'Hello World'

#左对齐、右对齐、居中
print(format(text, '>20'))    # "         Hello World"
print(format(text, '<20'))    # "Hello World         "
print(format(text, '^20'))    # "    Hello World     "

#format()也能接收填充字符
print(format(text, '=>20s'))  # '=========Hello World'
print(format(text, '*^20s'))  # '****Hello World*****'>

format() 函数的一个好处是它不仅适用于字符串。它可以用来格式化任何值,使得它非常的通用。比如,你可以用它来格式化数字

例:

x = 1.2345
print(format(x, '>10'))      # "    1.2345"
print(format(x, '^10.2f'))   # "   1.23   "

合并拼接字符串

使用 join() 拼接列表中的字符串

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

例:

words = ['金庸','小说','超级','好看']
print(' '.join(words))   # "金庸 小说 超级 好看"
print('-'.join(words))   # "金庸-小说-超级-好看"
print(''.join(words))    # ""金庸小说超级好看
使用 “+” 号拼接字符串

例:

a = 'I love'
b = 'you'
c = a + ' '+ b  
print(c)         # "I love you"
自动拼接字符串

如果你想在源码中将两个字面字符串合并起来,你只需要简单的将它们放到一起,
不需要用加号 (+)。

例:

a = 'Hello' 'World'
print(a)     #HelloWorld
最糟糙的字符串拼接

当我们使用加号 (+) 操作符去连接大量的字符串的时候是非常低效率的,因为加号连接会引起内存复制以及垃圾回收操作。特别的,你永远都不应像下面这样写字符串连接代码:

例:

words = ['金庸','小说','超级','好看']

# 糟糕的做法
s = ''
for i in words:
    s += i
print(s)                               #金庸小说超级好看

'''这种写法会比使用 join() 方法运行的要慢一些,因为每一次执行 += 操
作的时候会创建一个新的字符串对象。你最好是先收集所有的字符串片段然后再将它们连接起来。'''

#应该改成用 join()+生成器表达式更优
print(''.join(i for i in words))       #金庸小说超级好看

同样还得注意不必要的字符串连接操作。有时候程序员在没有必要做连接操作的时
候仍然多此一举。比如打印时:

例2:

print(a + ':' + b + ':' + c)  # Ugly
print(':'.join([a, b, c]))    # Still ugly
print(a, b, c, sep=':')       # Better

字符串中插入变量

使用 format() 插入变量

Python 并没有对在字符串中简单替换变量值提供直接的支持。但是通过使用字符
串的 format() 方法来解决这个问题。

例:

s = '{name} has {n} messages.'
print(s.format(name='bill', n=37))   #'bill has 37 messages.
结合使用 format_map() 和 vars() 插入变量

例:

s = '{name} has {n} messages.'
name = 'bill'
n = 37
print(s.format_map(vars()))    #'bill has 37 messages.

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

使用 textwrap 模块

例:

s = "Look into my eyes, look into my eyes, the eyes, the eyes, \
the eyes, not around the eyes, don't look around the eyes, \
look into my eyes, you're under."

#没格式化
print(s)
#Look into my eyes, look into my eyes, the eyes, the eyes, the eyes, not around the eyes, don't look around the eyes, look into my eyes, you're under.

import textwrap
#使用格式化,指定行长度
print(textwrap.fill(s, 70))
'''
Look into my eyes, look into my eyes, the eyes, the eyes, the eyes,
not around the eyes, don't look around the eyes, look into my eyes,
you're under.
'''

#使用格式化,指定行长度,并以空格符开头
print(textwrap.fill(s, 40, initial_indent='    '))
'''
    Look into my eyes, look into my
eyes, the eyes, the eyes, the eyes, not
around the eyes, don't look around the
eyes, look into my eyes, you're under.
'''

#使用格式化,指定行长度,除首行外全文以空格开头
print(textwrap.fill(s, 40, subsequent_indent='    '))
'''
Look into my eyes, look into my eyes,
    the eyes, the eyes, the eyes, not
    around the eyes, don't look around
    the eyes, look into my eyes, you're
    under.
'''

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

字符串中处理 html 和 xml

使用 html.escape() 处理

此方法可替换文本字符串中的 ‘<’ 或者 ‘>’

例:

mstr = '这是一个文本标签"<tag>text</tag>".'

print(mstr)                          # 这是一个文本标签<tag>text</tag>".

import html
#使用escape()
print(html.escape(mstr))             # 这是一个文本标签&quot;&lt;tag&gt;text&lt;/tag&gt;&quot;.
#使用escape(),但保留字符串中的双引号
print(html.escape(mstr,quote=False)) # 这是一个文本标签"&lt;tag&gt;text&lt;/tag&gt;".
运用参数 errors=‘xmlcharrefreplace’ 处理

此法用于 ASCII 文本,可将非 ASCII 文本变成对应的编码实体

例:

s = 'Spicy Jalapeño'
print(s.encode('ascii', errors='xmlcharrefreplace'))
# b'Spicy Jalape&#241;o'
使用 HTMLParser().unescape() 与 unescape() 处理

通常处理 HTML或者 XML 文本,试着先使用一个合适的 HTML 或者 XML 解析器。这些工具会自动替换这些编码值。但有时候,如果有一些含有编码值的原始文本,则需要手动去做替换,可使用 HTML 或者 XML 解析器的一些相关工具函数/方法比如:

例:

#例1:HTML文本
s = 'Spicy &quot;Jalape&#241;o&quot.'

from html.parser import HTMLParser

p = HTMLParser()
print(p.unescape(s))   # 'Spicy "Jalapeño".'

#例2:XML文本
t = 'The prompt is &gt;&gt;&gt;'

from xml.sax.saxutils import unescape
print(unescape(t))     # 'The prompt is >>>'

字节字符串的几个操作

字节字符串的“切片、搜索、分割、替换”

例:

data = b'Hello World'

#切片
print(data[0:5])     # b'Hello'
#搜索
print(data.startswith(b'Hello'))    # True
#分割字符串
print(data.split())    # [b'Hello', b'World']
#替换
print(data.replace(b'Hello', b'Hello Cruel'))    # b'Hello Cruel World'
使用正则表达式匹配字节字符串

使用正则表达式匹配字节字符串,但是正则表达式本身必须也是字节串。

例:

data = b'FOO:BAR,SPAM'

import re
print(re.split(b'[:,]',data))  #[b'FOO', b'BAR', b'SPAM']

【注意】 字节字符串的索引操作返回整数而不是单独字符

例:

a = 'Hello World'
print(a[0])  # 'H'
print(a[1])  # 'e'

b =  b'Hello World'
print(b[0])  # 72
print(b[1])  # 101
字节与字符的转换

例:

#字节转字符串
s = b'Hello World'
print(s)                   # b'Hello World'
print(s.decode('ascii'))   # Hello World

#字符串转字节
s = 'Hello World'
print(s)                   # 'Hello World'
print(s.encode())          # b'Hello World'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值