Python 字符串

Python 具有一个名为“str”的内置字符串类,其中包含许多便利功能(有一个名为“string”的较旧模块,您不应使用它)。字符串字面量可以用双引号或单引号括起来,不过单引号更常用。反斜杠转义方式在单引号和双引号字面量中均按常规方式运行,例如 \n \" \"。双引号字符串字面量可以包含单引号而没有任何混淆(例如 "I didn't do it"),同样,单引号字符串可以包含双引号。一个字符串字面量可以跨多行,但每行末尾都必须有反斜杠 \ 才能转义换行符。三引号 """ 或 ''' 内的字符串字面量可以跨多行文本。

Python 字符串是“不可变的”,这意味着它们在创建后无法更改(Java 字符串也使用此不可变样式)。由于字符串无法更改,因此我们在表示计算值时构建 *新* 字符串。例如,表达式 ('hello' + 'there') 包含 2 个字符串“hello”和“there”并构建一个新的字符串“hellothere”。

您可以使用标准的 [ ] 语法访问字符串中的字符;与 Java 和 C++ 一样,Python 也使用从零开始的索引,因此,如果 s 为“hello”,s[1] 为“e”。如果索引超出字符串的范围,Python 会引发错误。Python 样式(与 Perl 不同)是在无法指示操作时暂停,而不是仅仅构成一个默认值。简便的“Slice”语法(见下文)也适用于从字符串中提取任何子字符串。len(string) 函数会返回字符串的长度。[ ] 语法和 len() 函数实际上适用于所有序列类型,例如字符串、列表等。Python 会尝试让其操作在不同类型中以一致的方式运行。Python 新手小窍门:不要使用“len”作为变量名称,以免阻塞 len() 函数。“+”运算符可以将两个字符串串联起来。请注意,在下面的代码中,没有预先声明变量,只需将其赋值给变量即可。

  s = 'hi'
  print(s[1])          ## i
  print(len(s))        ## 2
  print(s + ' there')  ## hi there

与 Java 不同,“+”不会自动将数字或其他类型转换为字符串形式。str() 函数将值转换为字符串形式,以便它们可以与其他字符串组合。

  pi = 3.14
  ##text = 'The value of pi is ' + pi      ## NO, does not work
  text = 'The value of pi is '  + str(pi)  ## yes

对于数字,标准运算符 +、/、* 按常规方式工作。没有 ++ 运算符,但 +=、-= 等运算符可以运行。如果您希望使用整数除法,请使用 2 个斜杠,例如 6 // 5 为 1

“print”函数通常输出一个或多个 Python 项,后跟换行符。“原始”字符串字面量以“r”为前缀,传递所有字符,而不对反斜杠进行特殊处理,因此 r'x\nx' 的计算结果为长度为 4 的字符串“x\nx”。 “print”可以采用几个参数来更改输出内容的方式(请参阅 python.org 输出函数定义),例如将“end”设为“”,以便在输出完所有项后不再输出换行符。

  raw = r'this\t\n and that'

  # this\t\n and that
  print(raw)

  multi = """It was the best of times.
  It was the worst of times."""

  # It was the best of times.
  #   It was the worst of times.
  print(multi)

字符串方法

以下是一些最常见的字符串方法。方法类似于函数,但它是在对象“上运行”的。如果变量 s 是一个字符串,代码 s.lower() 会对该字符串对象运行 low() 方法并返回结果(在对象上运行方法的想法是构成面向对象编程 (OOP) 的基本构思之一)。以下是一些最常见的字符串方法:

  • s.lower()、s.upper() - 返回字符串的小写或大写版本
  • s.strip() - 返回一个字符串,该字符串移除了开头和结尾的空格
  • s.isalpha()/s.isdigit()/s.isspace()... - 测试所有字符串字符是否都属于不同的字符类
  • s.startswith('other'), s.endswith('other') - 测试字符串是否以给定的其他字符串开头或结尾
  • s.find('other') - 在 中搜索给定的其他字符串(非正则表达式),并返回开头的第一个索引,如果未找到,则返回 -1
  • s.replace('old', 'new') - 返回一个字符串,其中出现的所有“old”都已被“new”替换
  • s.split('delim') - 返回由指定分隔符分隔的子字符串列表。分隔符不是正则表达式,只是文本。'aaa,bbb,ccc'.split(',') -> ['aaa', 'bbb', 'ccc']。一种特殊情况是,s.split()(不带参数)会在所有空白字符上拆分。
  • s.join(list) -- 与 split() 相反,使用字符串作为分隔符将给定列表中的元素联接在一起。例如 '---'.join(['aaa', 'bbb', 'ccc']) -> aaa---bbb---ccc

在 Google 上搜索“python str”应该会将您引导至官方的 python.org 字符串方法,其中列出了所有 str 方法。

Python 没有单独的字符类型。相反,像 s[8] 这样的表达式会返回包含该字符的字符串长度 (length-1)。有了该 string-length-1,运算符 ==、<=, ... 都会按预期运行,因此大多数情况下,您不需要知道 Python 没有单独的标量“char”类型。

字符串切片

“切片”语法是一种引用序列子部分(通常为字符串和列表)的便捷方式。切片 s[start:end] 是从开始位置开始,一直延伸到结束,但不包括结束位置的元素。假设 s =“Hello”

包含字母索引 0 1 2 3 4 的字符串“hello”

  • s[1:4] 为“ell”- 从索引 1 开始,一直到索引 4 为止的字符
  • s[1:] 为“ello”- 如果省略索引,则默认为字符串的开头或结尾
  • s[:] 为“Hello”- 如果省略这两个参数,则始终为我们提供完整内容的副本(这是复制字符串或列表等序列的 Python 方法)
  • s[1:100] 为“ello”,如果索引过大,则会被截断至字符串长度

使用从零开始的标准索引编号可以轻松访问靠近字符串开头的字符。作为替代方案,Python 使用负数可以轻松访问字符串末尾的字符:s[-1] 表示最后一个字符“o”,s[-2] 表示“l”(倒数第二个字符),依此类推。负索引编号从字符串的末尾开始计数:

  • s[-1] 为“o”- 最后一个字符(从结尾起第 1 个字符)
  • s[-4] 为“e”- 距结尾第 4 位
  • s[:-3] 表示“他”,最多显示最后 3 个字符,但不包括最后 3 个字符。
  • s[-3:] 为“llo”,从第 3 个字符开始,一直到字符串的末尾。

对于任何索引 n,它是 s[:n] + s[n:] == s 的简洁切片。即使对于 n 为负或超出范围,也是如此。换句话说, s[:n] 和 s[n:] 始终将字符串划分为两个字符串部分,从而保留所有字符。正如我们稍后会在列表部分中看到的,切片也可以与列表配合使用。

字符串格式

Python 有一项非常实用的功能,那就是自动将对象转换为适合输出的字符串。两种内置方法来实现此目的:格式化的字符串字面量(也称为“f-strings”)和调用 str.format()。

设置了格式的字符串字面量

您经常会看到以下情况下使用格式化的字符串字面量:

  value = 2.791514
  print(f'approximate value = {value:.2f}')  # approximate value = 2.79

  car = {'tires':4, 'doors':2}
  print(f'car = {car}') # car = {'tires': 4, 'doors': 2}

格式化的文字字符串以“f”为前缀(例如用于原始字符串的“r”前缀)。 大括号“{}”之外的任何文本都将直接输出。“{}”中包含的表达式将按照格式规范中所述的格式规范输出。 您可以采取多种实用格式设置,包括截断、转换为科学记数法以及左/右/居中对齐。

当您要输出对象表,并希望代表不同对象属性的列对齐时,f 字符串会非常有用。

  address_book = [{'name':'N.X.', 'addr':'15 Jones St', 'bonus': 70},
      {'name':'J.P.', 'addr':'1005 5th St', 'bonus': 400},
      {'name':'A.A.', 'addr':'200001 Bdwy', 'bonus': 5},]

  for person in address_book:
    print(f'{person["name"]:8} || {person["addr"]:20} || {person["bonus"]:>5}')

  # N.X.     || 15 Jones St          ||    70
  # J.P.     || 1005 5th St          ||   400
  # A.A.     || 200001 Bdwy          ||     5

字符串百分比

Python 还有一个类似 printf() 的旧版工具,可用于组合字符串。% 运算符在左侧接受 printf 类型格式字符串(%d int、%s 字符串、%f/%g 浮点),以及右侧元组中的匹配值(元组由以英文逗号分隔的值组成,通常包含在圆括号内):

  # % operator
  text = "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down." % (3, 'huff', 'puff', 'house')

上面一行有点长 - 假设您想将其分成几行。您不能像在其他语言中一样直接拆分“%”之后的行,因为默认情况下,Python 将每行视为单独的语句(在加号的一侧,这就是我们不需要在每行上输入分号的原因)。要解决此问题,请在一个外括号中括住整个表达式,这样表达式就可以跨多行。这种跨行代码技术可与下面详细介绍的各种分组结构搭配使用:( )、[ ]、{ }。

  # Add parentheses to make the long line work:
  text = (
    "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down."
    % (3, 'huff', 'puff', 'house'))

这样更好,但该行仍然有点长。Python 允许您将一个行切成多个块,然后它会自动串联这些块。因此,为了进一步缩短这一行,我们可以执行以下操作:

  # Split the line into chunks, which are concatenated automatically by Python
  text = (
    "%d little pigs come out, "
    "or I'll %s, and I'll %s, "
    "and I'll blow your %s down."
    % (3, 'huff', 'puff', 'house'))

字符串(Unicode 与字节)

常规 Python 字符串是 Unicode 字符串。

Python 还支持由纯字节(由字符串字面量前面的“b”前缀表示)组成的字符串,例如:

> byte_string = b'A byte string'
> byte_string
  b'A byte string'

Unicode 字符串是与字节字符串不同的一种类型的对象,但如果传递的是任一类型字符串,各种库(如正则表达式)都能正常运行。

要将常规 Python 字符串转换为字节,请针对该字符串调用 encode() 方法。另一个方向是,字节字符串 extract() 方法会将已编码的普通字节转换为 Unicode 字符串:

> ustring = 'A unicode \u018e string \xf1'
> b = ustring.encode('utf-8')
> b
b'A unicode \xc6\x8e string \xc3\xb1'  ## bytes of utf-8 encoding. Note the b-prefix.
> t = b.decode('utf-8')                ## Convert bytes back to a unicode string
> t == ustring                         ## It's the same as the original, yay!

True

在文件读取部分,举例说明了如何打开包含某种编码的文本文件并读出 Unicode 字符串。

If 语句

Python 不使用 { } 封装 if/loops/function 等的代码块。相反,Python 使用冒号 (:) 和缩进/空格对语句进行分组。if 的布尔测试无需使用圆括号(与 C++/Java 的差异很大),并且可以包含 *elif* 和 *else* 子句(助记:“elif”与“else”一词的长度相同)。

任何值都可以用作 if-test。所有“零”值均计为 false:无、0、空字符串、空列表、空字典。还有一个布尔类型,它有两个值:True 和 False(转换为 int,分别为 1 和 0)。Python 具有常规比较操作:==、!=、<、<=、>、>=。与 Java 和 C 不同,== 重载后可以正确处理字符串。布尔运算符是拼出的单词 *and*、*or*、*not*(Python 不使用 C 样式的 && || !)。下面是全天提供饮品建议的健康应用的代码可能如下所示 - 请注意 then/else 语句的每个块如何以 : 开头,并且语句按其缩进分组:

  if time_hour >= 0 and time_hour <= 24:
    print('Suggesting a drink option...')
    if mood == 'sleepy' and time_hour < 10:
      print('coffee')
    elif mood == 'thirsty' or time_hour < 2:
      print('lemonade')
    else:
      print('water')

我发现,在输入上述类型的代码时,省略“:”是我最常遇到的语法错误,这可能是由于与我的 C++/Java 习惯相比,这个问题需要额外输入。此外,不要将布尔测试放在括号内 - 这是 C/Java 习惯。如果代码很短,您可以将代码放在“:”的同一行上,如下所示(这也适用于函数、循环等),但有些人觉得将内容放在单独的行中更方便阅读。

  if time_hour < 10: print('coffee')
  else: print('water')

练习:string1.py

如需练习本部分中的资料,请尝试基本练习中的 string1.py 练习。