python 字符串以什么结尾_前端语言和后端语言

Python (58) 2023-03-24 16:06

本节是第五讲的第四小节,上节为大家介绍了Python语言的数字类型包括(整型、布尔型、浮点型、复数型、十进制型),本节将为大家介绍项目中最常用类型字符串型,由于内容较多,分为上下两部分讲解。

字符串(Strings)

字符串是使用固定不变的str数据类型表示的,其中存放Unicode字符序列。str 数据类型可以作为函数进行调用,用于创建字符串对象——参数为空时返回一个空字符串,参数为非字符串类型时返回该参数的字符串形式,参数为字符串时返回该字符串的拷贝。str()函数也可以用作一个转换函数,此时要求第一个参数为字符串或可以转换为字符串的其他数据类型,其后跟随至多两个可选的字符串参数,其中一个用于指定要使用的编码格式,另一个用于指定如何处理编码错误。

前面我们注意到,字符串是使用引号创建的,可以使用单引号,也可以使用双引号,但是字符串两端必须相同。此外,我们还可以使用三引号包含的字符串——这是Python对起始端与终端都使用3个引号包含的字符串的叫法,例如:

text ="""A triple quoted string like this can include 'quotes' and

"quotes" without formality. We can also escape newlines \

so this particular string is actually only two lines long."""

a = "Single 'quotes' are fine; \"doubles\" must be escaped."

b = 'Single \'quotes\' must be escaped; "doubles" are fine.'

如果需要在通常的、引号包含的字符串中使用引号,在要使用的引号与包含字符串的引号不同时,可以直接使用该引号,而不需要进行格式化处理操作,但是如果相同,就必须对其进行转义。

Python使用换行作为其语句终结符,但是如果在圆括号内、方括号内、花括号内或三引号包含的字符串内则是例外。在三引号包含的字符串中,可以直接使用换行, 而不需要进行格式化处理操作。

Python字符串转义

\newline 忽略换行 \\ 反斜杠(\) \' 单引号(')

\" 双引号(“) \a ASCII 蜂鸣(BEL) \b ASCII 退格(BS)

\f ASCII 走纸(FF) \n ASCII 换行(LF) \N{name} 给定名称的Unicode字符

\ooo 给定八进制值的字符 \r ASCII回车符(CR) \t ASCII 制表符(TAB)

\uhhhh 给定16位十六进制值的Unicode字符 \v ASCII垂直指标(VT) \xhh 给定8位十六进制值的Unicode字符

如果需要写一个长字符串,跨越了2行或更多行,但是不使用三引号包含的字符串,那么有两种解决方法:

t = "This is not the best way to join two long strings" + \

"together since it relies on ugly newline escaping"

s = ("This is the nice way to join two long strings "

"together; it relies on string literal concatenation.")

注意上面第二种情况,我们必须使用圆括号将其包含在一起,构成一个单独的表达式——如果不使用圆括号,就只有第一个字符串对S进行赋值,第二个字符串则会导致 IndentationError 异常。Python 的"Idioms and Anti-Idioms" HOWTO文档建议总是使用圆括号将跨越多行的任何语句进行封装,而不使用转义的换行符,我们努力遵照这一建议。

由于.py文件默认使用UTF-8 Unicode编码,因此我们可以在字符串字面值中写入任意Unicode字符,而不拘形式。我们也可以使用十六进制转义序列(或使用Unicode名)将任意Unicode字符放置在字符串内,例如:

>>> euros = "€\N{euro sign}\u20AC\U000020AC"

>>> print(euros)

€€€€

上面的情况不能使用十六进制转义序列,因为本身限定在两个digits,无法超过 0xFF。要注意的是,Unicode字符名非大小写敏感,其中的空格也是可选的。

如果需要知道字符串中某个特定字符的Unicode字元(赋予Unicode编码中某个字符的整数值),那么可以使用内置的ord()函数,例如:

>>> ord(euros[0])

8364

>>> hex(ord(euros[0]))

'0x20ac‘

>>> s = "anarchists are " + chr(8734) + chr(0x23B7)

>>> s

'anarchists are ∞⎷'

>>> ascii(s)

"'anarchists are \\u221e\\u23b7'"

将表示有效字元的任意整数转换为相应的Unicode字符,这需要使用内置的chr()函数。如果在IDLE中输入本身,就输出其字符串形式。对于字符串,这意味着字符是包含在引号中输出的。如果只需要ASCII字符,就可以使用内置的ascii。函数,在可能的地方,该函数使用7比特表示形式返回其参数的对应ASCII表示,否则就使用最短的\xhh、\uhhhh或\Uhhhhhhhh进行转义。

比较字符串(Comparing Strings)

字符串支持通常的比较操作符<、<=、==、!=、>与>=,这些操作符在内存中逐个字节对字符串进行比较。遗憾的是,进行比较时(比如对字符串列表进行排序),存在两个问题,这两个问题都影响到每种使用Unicode字符串的程序设计语言,不是Python 特有的问题。

第一个问题是,有些Unicode字符可以使用两种或更多种字节序列表示。例如, 字符A⁰(Unicode字元0x00C5)可以3种不同的方式使用UTF-8编码的字节表示:[0xE2, 0x84, 0xAB]、[0xC3, 0x85]与[0x41, 0xCC, 0x8A]。幸运的是,我们可以解决这一问题。如果我们导入了 unicodedata模块,并以“NFKD”(这是使用的标准化方法,代表 Normalization Form Compatibility Decomposition")为第一个参数来调用 unicodedata.normalize(),则对包含字符A(使用任意一种有效字符序列表示)的字符串,该函数返回以UTF-8编码字节表示的字符串总是字节序列[0x41, 0xCC, 0x8A]。

第二个问题是,有些字符的排序是特定于某种语言的。一个实例是在瑞典语中,ā 排序在z之后,而在德语中,ā的排序与其被拼写为ae时一样。另一个实例是,在英语中,对¢排序时,与其为o一样,在丹麦语与挪威语中,则排序在z之后。这一类问题还有很多,由于同一个应用程序可能会由不同国家的人(因此所认为的排序顺序会不同)使用,使得这一问题变得更加复杂。此外,有时候字符串是不同语言混合组成的(比如,有些是西班牙语,有些是英语),而有些字符(比如箭头、dingbats与数学符号)并不真正具备有意义的排序位置。

作为一种策略(以便防止出错),Python并不进行推测。在字符串比较时,Python使用的是字符串的内存字节表示,此时的排序是基于Unicode字元的,比如对英语就是按ASCII顺序。对要比较的字符串进行小写或大写,会产生更贴近自然英语的排序。 标准化一般很少需要,除非字符串来自外部源(比如文件或网络socket),但即便是这些情况,一般也不必进行标准化,除非确实需要。

字符串分片与步距(Slicing and Striding Strings)

从要素3的讲解中我们知道,序列中的单个数据项或者字符串中的单个字符,可以使用数据项存取操作符[]来提取。实际上,这一操作符功能很丰富,其用途不仅仅局限于提取一个数据项或字符,还可以提取项或字符的整个分片(子序列),在这种情况下该操作符被用作分片操作符。

我们首先从提取单个字符开始。字符串的索引位置从0开始,直至字符串长度值减去1,但是使用负索引位置也是可能的——此时的计数方式是从最后一个字符到第一个字符。给定赋值操作s = "Light ray",

python 字符串以什么结尾_前端语言和后端语言_https://bianchenghao6.com/blog_Python_第1张

负索引值出人意料地有用,尤其是-1,这个值总是代表字符串的最后一个字符。 存取超过范围的索引位置(或空字符串中的索引位置)会产生IndexError异常。

分片操作符有3种语法格式:

seq[start]

seq[start:end]

seq[start:end:step]

其中,seq可以是任意序列,比如列表、字符串或元组。start、end与step必须都是整数(或存放整数的变量)。我们使用了第一种语法格式:从序列中提取从start开始的数据项。第二种语法从start开始的数据项(包含)到end结束的数据项(不包含) 提取一个分片。稍后我们将讨论第三种语法格式。

如果使用第二种语法格式(一个冒号),我们就可以忽略任意的整数索引值。如果忽略了所有起点索引值,就默认为0;如果忽略了终点索引值,就默认为len(seq),这意味着,如果忽略了两个索引值,比如,s[:],则与s[0:len(s)]是等同的,其作用都是提取--也就是复制整个序列。

给定赋值操作s = "The waxwork man",在字符串内插入子字符串的一种方法是混合使用带连接的分片,例如:

>>> s = s[:12] + "wo" + s[12:]

>>> s

The waxwork woman'

python 字符串以什么结尾_前端语言和后端语言_https://bianchenghao6.com/blog_Python_第2张

实际上,由于文本”wo”在原始字符串中,因此我们也可以写成s[:12] + s[7:9] + s[12:] 达到同样的效果。在涉及很多字符串时,使用+进行连接、使用+=进行追加等操作并不是特别高效, 如果需要连接大量的字符串,通常最好使用str.join()方法。

第三种分片语法格式(两个冒号)与第二种类似,区别在于不是提取每一个字符,而是每隔step个字符进行提取。与第二种语法类似,也可以忽略两个索引整数。如果忽略了起点索引值,那么默认为0—除非给定的是负的step值,此时起点索引值默认为-1;如果忽略终点索引值,那么默认为len(seq)——除非给定的是负的step值, 此时终点索引值默认为字符串起点前面。不过,不能忽略step,并且step不能为0。 如果不需要step,那么应该使用不包含step变量的第二种语法(一个冒号)。

给定赋值操作s = "he ate camel food",下图展示了字符串带步距的分片的两个实例。

python 字符串以什么结尾_前端语言和后端语言_https://bianchenghao6.com/blog_Python_第3张

上面我们使用默认的起点索引值与终点索引值,因此,s[::-2]从该字符串的最后一个字符开始,向该字符串的起点方向,每隔1个字符提取一个字符。类似地,s[::3]从 第一个字符开始,向该字符串的终点方向,每隔2个字符提取一个字符。

将分片与步距结合使用也是可能的,如下图所示。

python 字符串以什么结尾_前端语言和后端语言_https://bianchenghao6.com/blog_Python_第4张

更常见的情况下,步距是与字符串之外的序列类型一起使用的,但是也存在用于字符串的情况:

>>>s,s[::-1]

(’The waxwork woman', 'namow krowxaw ehT')

#step为-1意味着,每个字符都将被提取,方向为从终点到起点——因此会产生反转的字符串。

字符串操作符与方法(String Operators and Methods)

由于字符串是固定序列,所有可用于固定序列的功能都可用于字符串,包括使用 in进行成员关系测试,使用+=进行追加操作,使用*进行复制,使用*=进行增强的赋值复制等。在这一小节中,我们将在字符串的上下文中讨论所有这些操作,此外还讨论了很多字符串方法。

字符串方法

s.capitalize() 返回字符串s的副本,并将首字符变为大写,参见str.title()方法

s.center(width, char) 返回s中间部分的一个子字符串,长度为width,并使用空格或可选的char(长度为1 的字符串)进行填充。参考 str.ljust() 、str.rjust()与 str.format()

s.count(t, start, end) 返回字符串s中(或在s的start:end分片中)子字符串t出现的次数

s.encode(encoding, err) 返回一个bytes对象,该对象使用默认的编码格式或指定的编码格式来表示该字符串, 并根据可选的err参数处理错误

s.join(seq) 返回序列seq中每个项连接起来后的结果,并以s (可以为空)在每两项之间分隔

s.startswith(x, start, end) 如果s (或s的startend分片)以字符串x开始(或以元组x中的任意字符串开始),就返回 True,否则返回 False,参考 str.endswith()

s.endswith(x, start, end) 如果s (或在s的start:end分片)以字符串x (或元组x中的任意字符串)结尾,就返回 true,否则返回 False,参考 str.startswith()

s.expandtabs(size) 返回s的一个副本,其中的制表符使用8个或指定数量的空格替换

s.find(t, start, end) 返回t在s中(或在s的start:end分片中)的最左位置,如果没有找到,就返回-1;使用str.rfind()则可以发现相应的最右边位置;参考str.index()

s.format(...) 返回按给定参数进行格式化后的字符串副本

s.index(t, start, end) 返回t在s中的最左边位置(或在s的start:end分片中),如果没有找到,就产生ValueError 异常。使用str.rindex()可以从右边开始搜索。参见str.find()

s.isalnum() 如果s非空,并且其中的每个字符都是字母数字的,就返回True

s.isalpha() 如果s非空,并且其中的每个字符都是字母的,就返回True

s.isdecimal() 如果s非空,并且其中的每个字符都是Unicode的基数为10的数字,就返回True

s.isdigit() 如果s非空,并且每个字符都是一个ASCII数字,就返回True

s.isidentifier() 如果s非空,并且是一个有效的标识符,就返回True

s.islower() 如果s至少有一个可小写的字符,并且其所有可小写的字符都是小写的,就返回True, 参见 str.isupper()

s.isnumeric() 如果s非空,并且其中的每个字符都是数值型的Unicode字符,比如数字或小数,就返回 True

s.isprintable() 如果s非空,并且其中的每个字符被认为是可打印的,包括空格,但不包括换行,就返回True

s.isspace() 如果s非空,并且其中的每个字符都是空白字符,就返回True

s.istitle() 如果s是一个非空的首字母大写的字符串,就返回True,参见str.title()

s.isupper() 如果s至少有一个可大写的字符,并且所有可大写的字符都是大写,就返回True,参见 str.islower()

s.ljust(width, char) 返回长度为width的字符串(使用空格或可选的char (长度为1的字符串)进行填充)中左对齐的字符串s的一个副本,使用str.rjust()可以右对齐,str.center()可以中间对齐,参考 str.format()

s.maketrans() 与str.translate()类似

s.partition(t) 返回包含3个字符串的元组一一字符串s在t的最左边之前的部分、t、字符串s在t之后的部分。如果t不在s内,则返回s与两个空字符串。使用str.rpartition()可以在t最右边部分进行分区

s.replace(t,u,n) 返回s的一个副本,其中每个(或最多n个,如果给定)字符串t使用u替换

s.split(t, n) 返回一个字符串列表,要求在字符串t处至多分割n次,如果没有给定n,就分割尽可能多次,如果t没有给定,就在空白处分割。使用str.rsplit()可以从右边进行分割——只有在给定 n并且n小于可能分割的最大次数时才起作用

s.splitlines(f) 返回在行终结符处进行分割产生的行列表,并剥离行终结符(除非f为True)

s.lower() 将s中的字符变为小写,参见str.upper()

s.strip(chars) 返回s的一个副本,并将开始处与结尾处的空白字符(或字符串chars中的字符)移除,str.lstrip()仅剥离起始处的相应字符,str.rstrip()只剥离结尾处的相应字符

s.swapcase() 返回s的副本,.并将其中大写字符变为小写,小写字符变为大写,参考str.lower()与str.upper()

s.title() 返回s的副本,并将每个单词的首字母变为大写,其他字母都变为小写,参考str.istitle()

s.translate() 与str.maketrans()类似

s.upper() 返回s的大写化版本,参考str.lower()

s.zfill(w) 返回s的副本,如果比w短,就在开始处添加0,使其长度为w

字符串是序列,因此也是有大小的对象,我们可以以字符串为参数来使用len() 函数,返回值是字符串中的字符数(如果字符串为空,就返回0)。

我们已经知道,在字符串的操作中,+操作符被重载用于实现字符串连接。如果需要连接大量的字符串,使用str.join()方法是一种更好的方案。该方法以一个序列作为参数(比如,字符串列表或字符串元组),并将其连接在一起存放在一个单独的字符 串中,并将调用该方法的字符串作为分隔物添加在每两项之间,例如:

>>> treatises = ["Arithmetica", "Conics", "Elements"]

>>> " ".join(treatises)

'Arithmetica Conics Elements'

>>> "-<>-".join(treatises)

'Arithmetica-<>-Conics-<>-Elements'

>>> "".join(treatises)

'ArithmeticaConicsElements'

第一个实例或许是最常见的,连接一个单独的字符,这里是空格。第三个实例纯粹是连接,使用空字符串意味着字符串序列在连接时中间不使用任何填充。

str.join()方法也可以与内置的reversed()函数一起使用,以实现对字符串的反转, 比如,"".join(reversed(s))。当然,通过步距也可以更精确地获取同样的结果,比如, s[::-1]。

#*操作符提供了字符串复制功能:

>>> s = "=" * 5

>>> print(s)

=====

>>> s *= 10 #也可以使用复制操作符*的增强版进行赋值

>>> print(s)

==================================================

在用于字符串时,如果成员关系操作符in左边的字符串参数是右边字符串参数的 一部分,或者相等,就返回True。

如果我们需要在某个字符串中找到另一个字符串所在的位置,有两种方法,一种是使用str.index()方法,该方法返回子字符串的索引位置,或者在失败时产生一个 ValueError异常。另一种是使用str.find()方法,该方法返回子字符串的索引位置,或者在失败时返回-1。这两种方法都把要寻找的字符串作为第一个参数,还可以有两个可选的参数,其中第二个参数是待搜索字符串的起始位置,第三个则是其终点位置。

使用哪种搜索方法纯粹是个人爱好与具体场景,尽管如果搜索多个索引位置,使用str.index()方法通常会生成更干净的代码,如下面两个等价的函数所展示的:

def extract_from_tag(tag, line):

opener = "<" + tag + ">"

closer = "</"+ tag + ">"

try:

i = line.index(opener)

start = i + len(opener)

j = line.index(closer, start)

return line[start:j]

except ValueError:

return None

def extract_from_tag(tag, line):

opener = "<" + tag + ">"

closer = "</"+ tag + ">"

i = line.find(opener)

if i != -1:

start = i + len(opener)

j = line.find(closer, start)

if j != -1:

return line[start:j]

return None

两个版本的extract_from_tag()函数的作用是完全一致的。比如,extract_from_tag ("red”,”what a <red>rose<red> this is”)返回字符串"rose"。左面这一版本的异常处理部分更清晰地布局在其他代码之外,明确地表示了如何处理错误;右边版本的错误返回值则将分散了错误处理的不同情况。

方法 str.count()、str.find()、 str.rfind()、 str.index()、 str.rindex()与 str. startswith()、str.endswith()都接受至多两个可选的参数:起点位置与终点位置。这里给出两个等价的语句,并假定s是一个字符串:

s.count("m",6) == s[6:].count("m")

s.count("m",5, -3) == s[5:-3].count("m")

可以看出,接受起点与终点索引位置作为参数的方法可以运作在由这些索引值指定的字符串分片上。

下面看另一对等价的代码,主要是为了明确str.partition()的作用:

result=s.rpartition("/")

i = s.rfind("/")

if i == -1:

result = "","",s

else:

result =s[:i],s[i],s[i+1:]

左面的代码段与右面的代码段并不完全等价,因为右面还创建了一个新变量i。注意我们可以直接分配元组,而不拘于形式。两边的代码都是搜索/的最右边出现,如果字符串s ="/usr/local/bin/firefox",那么两个代码段都会产生同样的结果:('usr/local/bin','/','firefox')。

下面的语句同时使用 str.endswith()与str.lower()来打印文件名 如果该文件是一个JPEG文件:

if filename.lower().endswith((".jpg", ".jpeg")):

print(filename, "is a JPEG image")

>>> "917.5".isdigit(), "".isdigit(), "-2".isdigit(), "203".isdigit()

(False, False, False, True)

is*()方法工作的基础是Unicode字符分类,比如,以字符串"\N{circled digit two}03" 与"203"为参数调用str.isdigit()都会返回True。出于这一原因,我们不能因为isdigit() 函数返回True就判断某个字符串可以转换为整数。

从外部源(其他程序、文件、网络连接尤其是交互式用户)接受字符串时,字符串可能包含不需要的开始空白字符与结尾空白字符。我们可以使用str.lstrip()来剥离左边的空白字符,也可以使用str.rstrip()来剥离右边的空白字符,或者使用str.strip()同时剥离两边的空白字符。我们也可以使用一个字符串作为参数来调用剥离方法,这种情况下,每个字符的每个出现都将被从合适的位置剥离,例如:

>>> s ="\t no parking "

>>> s.lstrip(), s.rstrip(), s.strip()

('no parking ','\t no parking','no parking')

>>> ”<[unbracketed]>".strip("[]<>")

'unbracketed'

>>>"<[unbracketed]>".replace("<[","").replace("]>","")

'unbracketed'

我们可以使用str.replace()方法来在字符串内进行替换。这一方法以两个字符串作为参数,并返回该字符串的副本(其中第一个字符串的所有出现都被第二个字符串所替代)。如果第二个字符串为空,那么这一函数的实际效果是删除第一个字符串的所有出现。

一个频繁遇到的需求是将字符串分割为一系列子字符串。比如,我们有一个文本文件,需要将其中的数据进行处理,要求每行一个记录,每个记录的字段使用星号进行分隔。为此,可以使用str.split()方法,并以待分割的字符串作为第一个参数,以要分割的最大子数据段数为可选的第二个参数。如果再不指定第二个参数,该方法就会进行尽可能多的分割。下面给出一个实例:

>>> record = "Leo Tolstoy*1828-8-28*1910-11-20"

>>> fields = record.split("*")

>>> fields

['Leo Tolstoy1, '1828-8-28', '1910-11 -20']

以上面的结果为基础,可以使用str.split()方法对出生日期与死亡日期进行进一步的分割,以便计算其寿命(给定或接受一个年份值)。上面的代码中,我们必须使用int()方法将年份从字符串转换为整数,除此之外, 该代码段是很直接的。我们也可以从fields列表中获取年份,比如,year_bom = int(fields[1].split("-")[0])。

>>> born = fields[1].split("-")

>>> born

['1828','8','28']

>>> died = fields[2].split("-")

>>> print("lived about", int(died[0]) - int(bom[0]), "years")

lived about 82 years

str.maketrans()方法用于创建字符间映射的转换表,该方法可以接受一个、两个或三个参数,但是我们这里只展示最简单的(两个参数)调用方式,其中,第一个参数是一 个字符串,该字符串中的字符需要进行转换,第二个参数也是一个字符串,其中包含 的字符是转换的目标,这两个字符串必须具有相同的长度。str.translate()方法以转换表作为一个参数,并返回某个字符串根据该转换表进行转换后的副本。下面展示了如何将可能包含孟加拉数字的字符串转换为英文数字:

table ="".maketrans("\N(bengali digit zero}"

"\N(bengali digit one}\N{bengali digit two}"

"\N{bengali digit three}\N(bengali digit four}"

"\N{bengali digit five}\N(bengali digit six)"

"\N{bengali digit seven}\N(bengali digit eight}"

"\N{bengali digit nine}", "0123456789")

print("20749".translate(table)) # prints: 20749

print("\N{bengali digit two}07\N{bengali digit four)"

"\N{bengali digit nine}".translate(table)) # prints: 20749

从上面可以看出,在str.maketrans()调用内部以及第二个print()调用内部,我们利用了 Python的字符串字面值连接,使得字符串跨越了多行,而不需要对换行进行转义或使用显示的连接。

我们对空字符串调用了 str.maketrans()方法,因为该方法不关心其针对的具体字符串,而只是对其参数进行处理,并返回一个转换表*。str.maketrans()方法与str.translate()方法也可以用于删除字符,方法是将包含待删除字符的字符串作为第三个参数传递给 str.maketrans()。

以上内容部分摘自视频课程05后端编程Python-4字符串类型(上),更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。

发表回复