字符串和文本

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

问题:

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

解决方案:

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

1 import re
2 line = 'asdf fjdk; afed, fjek,asdf, foo'
3 result = re.split(r'[,;s+]s*',line)
4 print(result)

以上代码运行的结果为:

['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

字符串开头或结尾匹配

问题:

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

解决方案:

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

1 filename = 'spam.txt'
2 print(filename.endswith('.txt'))
3 print(filename.startswith('file:'))
4 
5 url = 'http://www.python.org'
6 print(url.startswith("http:"))

以上代码运行的结果为:

True
False
True

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

1 import os
2 filenames = os.listdir("D:/ENVS/test")
3 
4 print("D:/ENVS/test的目录下有:",filenames)
5 print("匹配以txt py结尾的文件",[file for file in filenames if file.endswith((".txt",".py"))])
6 print("filter的写法,匹配以txt xlsx的文件:",list(filter(lambda file:file.endswith((".txt",".xlsx")),filenames)))

以上代码运行的结果为:

D:/ENVS/test的目录下有: ['1.txt.txt', 're.txt', 'test.xlsx', 'toutiao.py', 'yizhibo_v3.py', 'youtube.py', '用户信息.xlsx']
匹配以txt py结尾的文件 ['1.txt.txt', 're.txt', 'toutiao.py', 'yizhibo_v3.py', 'youtube.py']
filter的写法,匹配以txt xlsx的文件: ['1.txt.txt', 're.txt', 'test.xlsx', '用户信息.xlsx']

用Shell 通配符匹配字符串

问题:

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

解决方法:

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

 1 from fnmatch import fnmatch, fnmatchcase
 2 
 3 r1 = fnmatch('foo.txt', '*.txt')
 4 print(r1)
 5 
 6 r2 = fnmatch('foo.txt', '?oo.txt')
 7 print(r2)
 8 
 9 r3 = fnmatch('Dat45.csv', 'Dat[0-9]*')
10 print(r3)
11 
12 names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']
13 name_list = [name for name in names if fnmatch(name,"Dat*.csv")]
14 print(name_list)

以上代码运行的结果为:

True
True
True
['Dat1.csv', 'Dat2.csv']

如果你对匹配的内容的返回结果敏感,可以使用fnmatchcase() 来代替。它完全使用你的模式大小写匹配。比如:

from fnmatch import fnmatchcase,fnmatch
#fnmatchcase函数大小写敏感
print(fnmatchcase('foo.txt', '*.TXT'))

#fnmatch函数大小写不敏感
print(fnmatch('foo.txt', '*.TXT'))

这两个函数通常会被忽略的一个特性是在处理非文件名的字符串时候它们也是很有用的。比如,假设你有一个街道地址的列表数据:

1 from fnmatch import fnmatchcase,fnmatch
2 
3 addresses = ['5412 N CLARK ST','1060 W ADDISON ST','1039 W GRANVILLE AVE','2122 N CLARK ST','4802 N BROADWAY',]
4 print(list(filter(lambda add:fnmatchcase(add, "* ST"),addresses)))
5 
6 print([addr for addr in addresses if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')])

以上代码运行的结果为:

['5412 N CLARK ST', '1060 W ADDISON ST', '2122 N CLARK ST']
['5412 N CLARK ST']

总结:

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

字符串匹配和搜索

问题:

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

解决方案:

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

 1 text = 'yeah, but no, but yeah, but no, but yeah'
 2 
 3 #判断text是否以yeah开头
 4 print(text.startswith("yeah"))
 5 
 6 #匹配text是否以no结尾
 7 print(text.endswith("no"))
 8 
 9 #查找text中no的索引起始点
10 print(text.find('no'))
11 print(text[10:12])

以上代码运行的结果:

True
False
10
no

对于复杂的匹配需要使用正则表达式和re 模块。为了解释正则表达式的基本原理,假设你想匹配数字格式的日期字符串比如11/27/2012 ,你可以这样做:

 1 import re
 2 
 3 text1 = '11/27/2012'
 4 text2 = 'Nov 27, 2012'
 5 
 6 #匹配text1是否以数字(d+)开头
 7 def year(match_year):
 8     if re.match(r'd+/d+/d+', match_year):
 9         print("{} yes".format(match_year))
10     else:
11         print("{} no".format(match_year))
12 
13 year(text1)
14 
15 year(text2)

以上代码运行的结果:

11/27/2012 yes
Nov 27, 2012 no

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

1 import re
2 text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
3 print(re.findall(r"d+/d+/d+",text))

以上代码运行的结果:

['11/27/2012', '3/13/2013']

 捕获分组可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来。

1 import re
2 datepat = re.compile(r'(d+)/(d+)/(d+)')
3 m = datepat.match('11/27/2012')
4 print(m.group())
5 print("month:", m.group(1))
6 print("day:", m.group(2))
7 print("year:", m.group(

以上代码运行的结果:

11/27/2012
month: 11
day: 27
year: 2012

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

 1 import re
 2 text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
 3 datepat = re.compile(r'(d+)/(d+)/(d+)')
 4 print(datepat.findall(text))
 5 #可迭代的对象
 6 print(datepat.finditer(text))
 7 
 8 #迭代输出结果
 9 for year in datepat.finditer(text):
10     print(year.groups())

以上代码运行的结果:

[('11', '27', '2012'), ('3', '13', '2013')]
<callable_iterator object at 0x0000024557C96A20>
('11', '27', '2012')
('3', '13', '2013')

总结:

  当写正则式字符串的时候,相对普遍的做法是使用原始字符串比如r'(nd+)/(nd+)/(nd+)' 。这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。如果不这样做的话,你必须使用两个反斜杠,类似'(nnd+)/(nnd+)/(nnd+)'。如果你打算做大量的匹配和搜索操作的话,最好先编译正则表达式,然后再重复使用它。模块级别的函数会将最近编译过的模式缓存起来,因此并不会消耗太多的性能,但是如果使用预编译模式的话,你将会减少查找和一些额外的处理损耗。

字符串搜索和替换

问题:

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

解决方法:

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

1 text = 'yeah, but no, but yeah, but no, but yeah'
2 print(text.replace("yeah","hey"))

以上运行代码的结果:

hey, but no, but hey, but no, but hey

对于复杂的模式,请使用re 模块中的sub() 函数。为了说明这个,假设你想将形式为11/27/2012 的日期字符串改成2012-11-27 。示例如下:

1 import re
2 text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
3 #前向引用,引用前面分组的内容
4 print(re.sub("(d+)/(d+)/(d+)", r"3-2-1", text))

以上代码运行的结果:

Today is 2012-27-11. PyCon starts 2013-13-3.

sub() 函数中的第一个参数是被匹配的模式,第二个参数是替换模式。反斜杠数字比如n3 指向前面模式的捕获组。

对于更加复杂的替换,可以传递一个替换回调函数来代替,比如:

 1 import re
 2 from calendar import month_abbr
 3 
 4 text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
 5 datepat = re.compile(r'(d+)/(d+)/(d+)')
 6 def change_date(m):
 7     mon_name = month_abbr[int(m.group(1))]
 8     return "{} {} {}".format(m.group(2), mon_name, m.group(3))
 9 
10 result = datepat.sub(change_date, text)
11 print(result)

以上代码运行的结果:

Today is 27 Nov 2012. PyCon starts 13 Mar 2013.

一个替换回调函数的参数是一个match 对象,也就是match() 或者find() 返回的对象。使用group() 方法来提取特定的匹配部分。回调函数最后返回替换字符串。

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

问题:

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

解决方案:

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

 1 import re
 2 
 3 text = 'UPPER PYTHON, lower python, Mixed Python'
 4 #匹配Python字符大小写不敏感
 5 result = re.findall("python", text, flags=re.IGNORECASE)
 6 print(result)
 7 
 8 #通过大小写不明感,替换Python字符串为golang
 9 replace_text = re.sub("python", "golang", text, flags=re.IGNORECASE)
10 print(replace_text)

以上代码运行的结果:

['PYTHON', 'python', 'Python']
UPPER golang, lower golang, Mixed golang

最短匹配模式 

问题:

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

解决方案:

  这个问题一般出现在需要匹配一对分隔符之间的文本的时候(比如引号包含的字符串)。为了说明清楚,考虑如下的例子:

 1 import re
 2 
 3 str_pat = re.compile(r'"(.*)"')
 4 text1 = 'Computer says "no."'
 5 
 6 print(str_pat.findall(text1))
 7 
 8 text2 = 'Computer says "no." Phone says "yes."'
 9 print(str_pat.findall(text2))
10 
11 #非贪婪模式,最少匹配,做爬虫的时候,用的比较多一些
12 new_str_pat = re.compile(r'"(.*?)"')
13 print(new_str_pat.findall(text2))

以上代码运行的结果:

['no.']
['no." Phone says "yes.']
['no.', 'yes.']

总结:

  在这个例子中,模式r'n"(.*)n"' 的意图是匹配被双引号包含的文本。但是在正则表达式中* 操作符是贪婪的,因此匹配操作会查找最长的可能匹配。于是在第二个例子中搜索text2 的时候返回结果并不是我们想要的。为了修正这个问题,可以在模式中的* 操作符后面加上? 修饰符。这样就使得匹配变成非贪婪模式,从而得到最短的匹配,也就是我们想要的结果 

多行匹配模式

问题:

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

解决方案:

  这个问题很典型的出现在当你用点(.) 去匹配任意字符的时候,忘记了点(.) 不能匹配换行符的事实。比如,假设你想试着去匹配C 语言分割的注释:

 1 import re
 2 
 3 comment = re.compile(r'/*(.*?)*/')
 4 text1 = '/* this is a comment */'
 5 text2 = '''/* this is a 
 6         multiline comment */
 7         '''
 8 print(comment.findall(text1))
 9 print(comment.findall(text2))
10 
11 #为了修正这个问题
12 comment = re.compile(r'/*(.*?)*/', re.DOTALL)
13 print(comment.findall(text2))

以上代码运行的结果:

[' this is a comment ']
[]
[' this is a 
        multiline comment ']

将Unicode 文本标准化

问题:

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

解决方案:

  在Unicode 中,某些字符能够用多个合法的编码表示。为了说明,考虑下面的这个例子:

 1 s1 = 'Spicy Jalapeu00f1o'
 2 s2 = 'Spicy Jalapenu0303o'
 3 #打印s1的信息并打印字符串的长度
 4 print("s1:", s1, "s1的长度:", len(s1))
 5 #打印s2的信息并打印字符串的长度
 6 print("s2:", s2, "s2的长度", len(s2))
 7 
 8 #解决输出不是一致的问题
 9 import unicodedata
10 t1 = unicodedata.normalize("NFC", s1)
11 t2 = unicodedata.normalize("NFC", s2)
12 print("t1:", t1, "t1的长度为:", len(t1))
13 print("t2:", t2, "t2的长度为:", len(t2))
14 print("-"*50)
15 t3 = unicodedata.normalize("NFD", s1)
16 t4 = unicodedata.normalize("NFD", s2)
17 print("t3:", t3, "t3的长度为:", len(t3))
18 print("t4:", t4, "t4的长度为:", len(t4))

以上代码运行的结果:

s1: Spicy Jalapeño s1的长度: 14
s2: Spicy Jalapeño s2的长度 15
t1: Spicy Jalapeño t1的长度为: 14
t2: Spicy Jalapeño t2的长度为: 14
--------------------------------------------------
t3: Spicy Jalapeño t3的长度为: 15
t4: Spicy Jalapeño t4的长度为: 15

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

Python 同样支持扩展的标准化形式NFKC 和NFKD,它们在处理某些字符的时候增加了额外的兼容特性。比如:

 1 import unicodedata
 2 s = 'ufb01' # A single character
 3 s1 = unicodedata.normalize('NFD', s)
 4 s2 = unicodedata.normalize('NFKD', s)
 5 s3 = unicodedata.normalize('NFKC', s)
 6 #打印三个变量的字符串
 7 print(s1, s2, s3)
 8 #判断三个变量的字符串是否相当
 9 print(s1==s2==s3)
10 #判断s2,s3兼容格式的字符串是否一样
11 print(s2==s3)

以上代码运行的结果:

fi fi fi
False
True

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

问题:

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

解决方案:

  strip() 方法能用于删除开始或结尾的字符。lstrip() 和rstrip() 分别从左和从右执行删除操作。默认情况下,这些方法会去除空白字符,但是你也可以指定其他字符。比如:

 1 s = ' hello world 
'
 2 result = s.strip()
 3 #打印开头的空格及结尾的回车
 4 print(result)
 5 #去除左边的,并没有把结尾的回车去除掉
 6 print(s.lstrip())
 7 #去除右边的,把结尾的回车去掉了,和第一个效果一样
 8 print(s.rstrip())
 9 print("-"*30)
10 t = '-----hello====='
11 #去除最左边的-
12 print(t.lstrip('-'))
13 #去除最开头的-以及结尾的=
14 print(t.strip('-='))

以上代码运行的结果:

hello world
hello world 

 hello world
------------------------------
hello=====
hello

审查清理文本字符串

问题:

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

解决方法:

  文本清理问题会涉及到包括文本解析与数据处理等一系列问题。在非常简单的情形下,你可能会选择使用字符串函数(比如str.upper() 和str.lower() ) 将文本转为标准格式。使用str.replace() 或者re.sub() 的简单替换操作能删除或者改变指定的字符序列。然后,有时候你可能还想在清理操作上更进一步。比如,你可能想消除整个区间上的字符或者去除变音符。为了这样做,你可以使用经常会被忽视的str.translate()方法。为了演示,假设你现在有下面这个凌乱的字符串:

1 s = 'pýtĥöñfis	awesome
'
2 print(s)
3 #定义一个可以替换字符的字典
4 remap = { ord('	') : ' ',ord('f') : ' ', ord('
') : None }
5 print(remap)
6 #替换到不需要的字符
7 result = s.translate(remap)
8 print(result)

以上代码运行的结果:

pýtĥöñis    awesome

{9: ' ', 12: ' ', 13: None}
pýtĥöñ is awesome

正如你看的那样,空白字符nt 和nf 已经被重新映射到一个空格。回车字符r 直接被删除。

 1 import unicodedata
 2 import sys
 3 
 4 s = 'pýtĥöñfis	awesome
'
 5 #通过使用dict.fromkeys() 方法构造一个字典,每个Unicode 和音符作为键,对于的值全部为None
 6 cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode) if unicodedata.combining(chr(c)))
 7 #将原始输入标准化为分解形式字符
 8 b = unicodedata.normalize("NFD", s)
 9 print(b)
10 #调用translate 函数删除所有重音符
11 result  = b.translate(cmb_chrs)
12 print(result)

以上代码运行的结果为:

pýtĥöñis    awesome

pythonis    awesome

总结:

  文本字符清理一个最主要的问题应该是运行的性能。一般来讲,代码越简单运行越快。对于简单的替换操作, str.replace() 方法通常是最快的,甚至在你需要多次调用的时候。

 字符串对齐

问题:

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

解决方案

  对于基本的字符串对齐操作,可以使用字符串的ljust() , rjust() 和center()方法。比如:

1 text = 'Hello World'
2 print(text.ljust(20,"-"))
3 print(text.rjust(20,"*"))
4 print(text.center(20,"-"))

以上代码运行的结果为:

Hello World---------
*********Hello World
----Hello World-----

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

1 text = 'Hello World'
2 #使用format格式化文本
3 print(format(text, ">20s")+".")
4 print(format(text, "<20s")+".")
5 print(format(text, "=>20s"))
6 print(format(text, "*^20s"))
7 print("-"*30)
8 print("{:>10s} {:>10s}".format("Hello", "World"))

以上代码运行的结果为:

         Hello World.
Hello World         .
=========Hello World
****Hello World*****
------------------------------
     Hello      World

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

合并拼接字符串

问题:

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

解决方案:

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

 1 parts = ['Is', 'Chicago', 'Not', 'Chicago?']
 2 r1 = ' '.join(parts)
 3 print('r1的结果:', r1)
 4 
 5 r2 = ','.join(parts)
 6 print('r2的结果:', r2)
 7 
 8 a = 'Is Chicago'
 9 b = 'Not Chicago?'
10 r3 = a + ' ' + b
11 print('r3的结果:', r3)
12 
13 r4 = 'Hello' 'World'
14 print('r4的结果:', r4)

以上代码运行的结果为:

r1的结果: Is Chicago Not Chicago?
r2的结果: Is,Chicago,Not,Chicago?
r3的结果: Is Chicago Not Chicago?
r4的结果: HelloWorld

字符串中插入变量

问题:

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

解决方案:

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

1 s = '{name} has {n} message.'
2 result = s.format(name='demon', n=10)
3 print(result)
4 name = 'demon'
5 n = '20'
6 #vars()的效果等同于{"name":'demon', 'n':20}
7 print(s.format_map(vars()))
8 print('*'*40)
9 print(s.format_map({"name":'demon', 'n':20}))

以上代码运行的结果为:

demon has 10 message.
demon has 20 message.
****************************************
demon has 20 message.

以指定列宽格式化字符串

问题:

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

解决方案:

  使用textwrap 模块来格式化字符串的输出。比如,假如你有下列的长字符串:

 1 import textwrap
 2 
 3 text = "Look into my eyes, look into my eyes, the eyes, the eyes, 
 4 the eyes, not around the eyes, don't look around the eyes, 
 5 look into my eyes, you're under."
 6 
 7 result = textwrap.fill(text, 70)
 8 print(result + '
')
 9 
10 #开头空两个字符的长度
11 r1 = textwrap.fill(text, 70, initial_indent='  ')
12 print("r1的输出效果:")
13 print(r1)

以上代码运行的结果为:

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.

r1的输出效果:
  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.

字符串令牌解析

问题:

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

解决方案:

  假如你有下面这样一个文本字符串:

 1 import re
 2 from collections import namedtuple
 3 #要计算的表达式
 4 text = 'foo = 23 + 42 * 10'
 5 #令牌
 6 tokens = [('NAME', 'foo'), ('EQ','='), ('NUM', '23'), ('PLUS','+'),
 7         ('NUM', '42'), ('TIMES', '*'), ('NUM', '10')]
 8 
 9 NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
10 NUM = r'(?P<NUM>d+)'
11 PLUS = r'(?P<PLUS>+)'
12 TIMES = r'(?P<TIMES>*)'
13 EQ = r'(?P<EQ>=)'
14 WS = r'(?P<WS>s+)'
15 
16 master_pat = re.compile('|'.join([NAME, NUM, PLUS, TIMES, EQ, WS]))
17 scanner = master_pat.scanner('foo = 42')
18 print(scanner)
19 
20 def generate_tokens(pat, text):
21     Token = namedtuple("Token", ('type', 'value'))
22     scanner = pat.scanner(text)
23     for m in iter(scanner.match, None):
24         yield Token(m.lastgroup, m.group())
25 
26 #生成器
27 tokens = (tok for tok in generate_tokens(master_pat, text) if tok.type != 'WS')
28 
29 for tok in tokens:
30     print(tok)

以上代码运行的结果为:

<_sre.SRE_Scanner object at 0x000002D55FBE8300>
Token(type='NAME', value='foo')
Token(type='EQ', value='=')
Token(type='NUM', value='23')
Token(type='PLUS', value='+')
Token(type='NUM', value='42')
Token(type='TIMES', value='*')
Token(type='NUM', value='10')

字节字符串上的字符串操作:

问题:

  你想在字节字符串上执行普通的文本操作(比如移除,搜索和替换)。

解决方案:

  字节字符串同样也支持大部分和文本字符串一样的内置操作。比如:

 1 data = b'Hello World'
 2 r1 = data[:5]
 3 print(r1)
 4 
 5 print(data.startswith(b'Hello'))
 6 r2 = data.split()
 7 print(r2)
 8 
 9 #上面的操作完全适用于数组
10 print("数组的输出:".center(40, "*"))
11 data = bytearray(b'Hello World')
12 print(data[:5])
13 print(data.startswith(b'Hello'))
14 print(data.split())
15 
16 #可以使用正则去匹配,不过如果使用正则去匹配的话,一定也要是字节串(b'')
17 print(format("re字节匹配内容", "-^30s"))
18 data = b'FOO:BAR,SPAM'
19 import re
20 result = re.split(b'[:]', data)
21 print(result)

以上代码运行的结果为:

b'Hello'
True
[b'Hello', b'World']
*****************数组的输出:*****************
bytearray(b'Hello')
True
[bytearray(b'Hello'), bytearray(b'World')]
-----------re字节匹配内容-----------
[b'FOO', b'BAR,SPAM']

 如果你想格式化字节字符串,你得先使用标准的文本字符串,然后将其编码为字节字符串。比如:

 

原文地址:https://www.cnblogs.com/demon89/p/7268668.html