字符串 str
在 Python 2 中,str 是字节串(byte string),而非字符序列。每个元素是一个字节(0–255 的整数),在 ASCII 范围内(0–127)可以表示英文字母、数字和常见符号。这是 Python 2 字符串系统最容易被误解的地方,也是它与 Python 3 最根本的差异之一。
创建字符串
s1 = 'hello' # 单引号
s2 = "world" # 双引号
s3 = '''多行
字符串''' # 三引号,保留换行
s4 = """也可以
用双引号"""
单引号和双引号完全等价,选择哪个取决于字符串内容:如果字符串包含单引号,就用双引号包裹,反之亦然。这样可以避免转义:
print "It's a nice day" # 正确
print 'It\'s a nice day' # 也可以,但多了反斜杠
字符串是不可变的
str 是不可变序列,创建后不能修改任何字符:
s = "hello"
s[0] = "H" # TypeError: 'str' object does not support item assignment
所有看似"修改"字符串的操作,实际上都是创建新字符串:
s = "hello"
s2 = s.capitalize() # 创建新字符串 "Hello",s 不变
print s # "hello"
print s2 # "Hello"
这种不可变性带来了两个好处:一是字符串可以作为字典的键(字典键必须可哈希,而可变对象不可哈希);二是多个变量可以安全地共享同一个字符串对象,无需担心被意外修改。
索引与切片
字符串支持序列的所有标准操作:
s = "Python"
# 索引
print s[0] # 'P'
print s[-1] # 'n',倒数第一个
# 切片 [start:stop:step]
print s[0:2] # 'Py',左闭右开
print s[2:] # 'thon',从索引 2 到末尾
print s[:4] # 'Pyth',从开头到索引 4(不含)
print s[::2] # 'Pto',每隔一个取一个
print s[::-1] # 'nohtyP',反转
切片不会越界报错,而是自动截断到有效范围:
s = "hi"
print s[0:100] # 'hi',不会报错
print s[5:10] # '',空字符串
转义序列
反斜杠 \ 用于引入特殊字符:
print "Line 1\nLine 2" # \n 换行
print "Tab\there" # \t 制表符
print "C:\\Users\\Bob" # \\ 反斜杠本身
print 'It\'s mine' # \' 单引号
print "She said \"Hi\"" # \" 双引号
如果字符串中包含大量反斜杠(如 Windows 路径、正则表达式),可以使用原始字符串(raw string),前缀加 r 或 R:
path = r"C:\Users\Bob\Documents"
print path # C:\Users\Bob\Documents,不处理转义
pattern = r"\b\w+@\w+\.\w+"
print pattern # \b\w+@\w+\.\w+,正则表达式保留原样
注意:原始字符串的末尾不能是单个反斜杠,因为反斜杠会转义引号:r"C:\" 是语法错误。解决方法是拼接:r"C:\" + "\\" 或 "C:\\\"。
常用方法
s = " Hello, World! "
print s.strip() # "Hello, World!",去除两端空白
print s.lower() # " hello, world! "
print s.upper() # " HELLO, WORLD! "
print s.startswith("He") # False(前面有空格)
print s.find("World") # 10,找不到返回 -1
print s.replace("World", "Python") # " Hello, Python! "
print s.split(", ") # [' Hello', 'World! ']
print "-".join(["a", "b", "c"]) # "a-b-c"
find() 和 index() 的区别:find() 找不到返回 -1,index() 找不到抛出 ValueError:
print "abc".find("z") # -1
print "abc".index("z") # ValueError: substring not found
字符串格式化
Python 2 中最常用的格式化方式是 % 操作符:
name = "Alice"
age = 25
print "My name is %s, I am %d years old." % (name, age)
# My name is Alice, I am 25 years old.
常用格式符:
| 格式符 | 含义 | 示例 |
|---|---|---|
%s | 字符串 | "%s" % "hello" → "hello" |
%d | 整数 | "%d" % 42 → "42" |
%f | 浮点数 | "%f" % 3.14 → "3.140000" |
%.2f | 保留两位小数 | "%.2f" % 3.14159 → "3.14" |
%x | 十六进制 | "%x" % 255 → "ff" |
%o | 八进制 | "%o" % 8 → "10" |
%% | 字面量 % | "100%%" → "100%" |
str.format()(Python 2.6+)提供了更灵活的格式化:
print "{0} + {1} = {2}".format(1, 2, 3) # "1 + 2 = 3"
print "{name} is {age} years old".format(name="Tom", age=20)
编码陷阱
str 本质上是字节序列,它不知道自己的编码。如果文件头声明了 UTF-8,源文件中的 "你好" 会被编码为 6 个字节(\xe4\xbd\xa0\xe5\xa5\xbd),存储在 str 对象中。打印时,终端需要知道这 6 个字节是 UTF-8 编码,才能正确显示"你好"。
如果终端编码与文件编码不一致,就会出现乱码或 UnicodeEncodeError。这是 Python 2 字符串系统最痛苦的地方,也是 Python 3 将 str 改为 Unicode 的根本原因。