Python 字符串

Python 有一个名为“str”的内置字符串类。具有许多便捷功能(不应使用一个名为“string”的旧版模块)。字符串字面量可以使用双引号或单引号引起,不过单引号更为常用。在单引号和双引号字面量中,反斜杠转义会照常执行,例如\n \“\“带英文双引号的字符串字面量可包含单引号,毫不费力(例如,“I didn’t do it”),同样,带英文单引号的字符串也可包含双引号。字符串字面量可以跨多行,但每行的末尾都必须有一个反斜杠 \ 才能对换行符进行转义。三引号内的字符串字面量, """或“'”可以跨多行文本。

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

您可以使用标准的 [ ] 语法访问字符串中的字符,并且与 Java 和 C++ 一样,Python 也使用从 0 开始编制索引,因此如果 s 为“hello”,s[1] 是“e”。如果索引超出字符串的边界,则 Python 会引发错误。Python 样式(与 Perl 不同)是在无法判断要执行什么操作时停止运行,而不是仅设置一个默认值。便捷的“切片”语法(如下所示)也可以从字符串中提取任何子字符串。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

“平面广告”函数通常会输出一个或多个 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)

字符串方法

以下是一些最常见的字符串方法。方法类似于函数,只不过是在“on”上运行对象。如果变量 s 是一个字符串,则代码 s.lower() 会针对该字符串对象运行 lower() 方法并返回结果(在对象上运行一种方法是构成面向对象编程 (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' 的字符串已替换为“全新”
  • 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] 这样的表达式会返回包含该字符的字符串长度为 1。有了这个 string-length-1,运算符 ==、<=、... 一切都会按预期运行,所以大多数情况下您不需要知道 Python 没有单独的标量“char”类型。

字符串 Slice

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

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

  • s[1:4] 表示“ell”-- 从索引 1 开始并一直到索引 4(但不包括索引 4)的字符
  • s[1:] 是“ello”- 若省略索引,则默认为字符串的开头或结尾
  • s[:] 是“Hello”-- 同时省略这两者总是可以得到整个内容的副本(这是复制字符串或列表等序列的 pythonic 方式)
  • s[1:100] 是“ello”- 如果索引过大,则会被截断为字符串长度

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

  • s[-1] 为“o”-- 最后一个字符(从末尾开始第 1 个字符)
  • s[-4] 为“e”-- 倒数第 4 个
  • s[:-3] 是“He”-- 显示但不包含最后 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”前缀)。 大括号“{}”之外的任何文本会直接输出结果“{}”中包含的表达式是 均按照 格式规范 您可以对格式执行许多巧妙的操作,包括截断和 转换为科学记数法并采用左/右/居中对齐。

如果您要输出一个对象表,并希望 代表要对齐的不同对象属性的列

  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() 方法。从另一个方向来看,字节字符串 Decode() 方法会将已编码的普通字节转换为 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:None、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 练习。