字符串是编程中出现频率最高的数据类型之一——处理用户输入、读写文件、拼接 URL、格式化日志、拆解 CSV,几乎每个 Python 脚本都少不了它。前面 变量与基本数据类型 已经打过照面,这一篇要把 Python 字符串从零到能干活 讲完整:创建、索引、切片、常用方法(超过 30 个)、编码与字节、以及最容易踩的那几个坑。
一、字符串的创建 Python 字符串支持四种界定方式:
1 2 3 4 5 6 7 8 9 10 11 s1 = 'hello' s2 = "hello" s3 = '''多行 字符串''' s4 = """多行 字符串""" q1 = "He said 'hi'" q2 = 'It\'s ok' q3 = "It's ok"
惯例 :普通字符串用双引号,需要输出双引号的字符串用单引号,跨多行的用三引号。别纠结,一致就行。
转义字符 1 2 3 4 5 6 print ("换行\n再来一行" )print ("\t缩进" ) print ("反斜杠 \\" )print ("Unicode: 中文" ) print ("原生字符串 r'C:\Users\name'" ) print (r"原生字符串 r'C:\Users\name'" )
Windows 路径写字符串时务必加 r ,或者用双反斜杠、或者用正斜杠:
1 2 3 path = r"C:\Users\name\file.txt" path = "C:\\Users\\name\\file.txt" path = "C:/Users/name/file.txt"
二、字符串是不可变的 Python 字符串不可变 (immutable)——一旦创建,不能修改任何一个字符:
要”修改”字符串,你只能创造一个新字符串:
1 2 3 s = "H" + s[1 :] s = s.replace("h" , "H" ) s = s.upper()
这个特性的好处:字符串可以做字典的 key、可以放进 set、可以在多线程里安全共享。
三、索引与切片 字符串本质上是”字符的序列”,支持索引和切片(与列表一致):
1 2 3 4 5 6 7 8 9 10 s = "Python" print (s[0 ]) print (s[-1 ]) print (len (s)) print (s[0 :2 ]) print (s[2 :]) print (s[:3 ]) print (s[::-1 ]) print (s[::2 ])
切片永远返回新字符串 ,不会修改原字符串。切片深入讲解见 序列切片深入解析 。
四、遍历字符串 字符串可迭代,直接 for 循环即可:
1 2 3 4 5 6 7 8 for ch in "咖飞" : print (ch) for i, ch in enumerate ("Python" ): print (i, ch)
五、常用方法(按功能分组) 1. 大小写 1 2 3 4 5 6 7 s = "Hello, Python" print (s.upper()) print (s.lower()) print (s.title()) print (s.capitalize()) print (s.swapcase())
2. 检索 1 2 3 4 5 6 7 8 9 s = "hello world" print (s.find("o" )) print (s.rfind("o" )) print (s.index("o" )) print (s.count("l" )) print (s.startswith("he" )) print (s.endswith("ld" ))
3. 判断 1 2 3 4 5 6 7 print ("abc123" .isalnum()) print ("abc" .isalpha()) print ("123" .isdigit()) print (" " .isspace()) print ("ABC" .isupper()) print ("abc" .islower()) print ("Hello World" .istitle())
4. 修剪 1 2 3 4 5 6 7 8 9 10 11 12 s = " hello " print (repr (s.strip())) print (repr (s.lstrip())) print (repr (s.rstrip())) print ("__abc__" .strip("_" )) print ("www.baidu.com" .lstrip("w." )) print ("test_module.py" .removesuffix(".py" )) print ("Mr. Wang" .removeprefix("Mr. " ))
注意 strip("abc") 是去除”任意 a/b/c 字符”,不是去除子串 "abc"。用 removeprefix/removesuffix 才是去除子串。
5. 替换 1 2 3 s = "hello world hello" print (s.replace("hello" , "hi" )) print (s.replace("hello" , "hi" , 1 ))
6. 拆分与拼接 1 2 3 4 5 6 7 8 9 10 "a,b,c" .split("," ) "a b c" .split() "a,b,c" .rsplit("," , 1 ) "line1\nline2\nline3" .splitlines() "," .join(["a" , "b" , "c" ]) "\n" .join(["行1" , "行2" ]) "" .join(["a" , "b" , "c" ])
为什么用 join 不用 +? 循环里 += 拼接字符串每次都会创建新对象,是 O(n²);而 "".join(list) 是 O(n)。写循环拼接大量字符串时永远用 join:
1 2 3 4 5 6 7 result = "" for word in words: result += word + " " result = " " .join(words)
7. 填充与对齐 1 2 3 4 5 "5" .zfill(4 ) "abc" .ljust(10 , "-" ) "abc" .rjust(10 , "-" ) "abc" .center(10 , "-" )
在打印表格、生成对齐输出时很有用。
8. 编码相关 1 2 3 s = "咖飞" b = s.encode("utf-8" ) s2 = b.decode("utf-8" )
str 是 Unicode 字符串(人读的);
bytes 是字节序列(机器传的);
encode 把 str → bytes,decode 把 bytes → str;
中文一般用 UTF-8,遇到旧文件可能用 GBK。
六、格式化字符串(简版) 字符串格式化有三种主流方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 name = "咖飞" age = 3 print (f"我叫 {name} ,{age} 岁" )print (f"两位小数:{3.14159 :.2 f} " ) print (f"补 4 位:{7 :04d} " ) print ("我叫 {},{} 岁" .format (name, age))print ("我叫 {n},{a} 岁" .format (n=name, a=age))print ("我叫 %s,%d 岁" % (name, age))
新代码永远用 f-string 。format 和 % 只在维护老代码时才会遇到。
字符串格式化的完整讲解见 字符串格式化进阶 。
七、字符串常量 Python 标准库 string 里有一些方便的常量:
1 2 3 4 5 6 7 import stringprint (string.ascii_letters) print (string.ascii_lowercase) print (string.digits) print (string.punctuation) print (string.whitespace)
生成随机密码时特别好用:
1 2 3 4 5 6 7 8 import randomimport stringdef gen_password (length: int = 12 ) -> str : chars = string.ascii_letters + string.digits + string.punctuation return "" .join(random.choices(chars, k=length)) print (gen_password())
八、字符串与列表的互转 1 2 3 4 5 6 7 8 s = "咖飞" lst = list (s) back = "" .join(lst) sentence = "I love Python" words = sentence.split() back = " " .join(words)
九、一个完整例子:日志脱敏 我们把这一篇的知识揉到一起,写一个”手机号脱敏”工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 """把日志里的手机号和邮箱替换成脱敏形式。""" def mask_phone (phone: str ) -> str : """138****1234 形式。""" if len (phone) != 11 or not phone.isdigit(): return phone return phone[:3 ] + "*" * 4 + phone[-4 :] def mask_email (email: str ) -> str : """把 @ 前只保留首尾两个字符。""" if "@" not in email: return email name, domain = email.split("@" , 1 ) if len (name) <= 2 : masked = name else : masked = name[0 ] + "*" * (len (name) - 2 ) + name[-1 ] return f"{masked} @{domain} " def mask_line (line: str ) -> str : """对一行日志同时脱敏(简化版:这里只演示 str 方法,实际生产建议用 re)。""" words = line.split() return " " .join( mask_email(w) if "@" in w else mask_phone(w) if len (w) == 11 and w.isdigit() else w for w in words ) if __name__ == "__main__" : logs = [ "user 13812345678 login ok" , "notify kafei@example.com 已发送" , "顺序无关 admin 18899990000 alice@a.cn" , ] for line in logs: print (mask_line(line))
输出:
1 2 3 user 138****5678 login ok notify k****i@example.com 已发送 顺序无关 admin 188****0000 a****e@a.cn
真实生产环境的日志脱敏建议用 正则表达式 re 模块 ,本例只是演示字符串方法组合的威力。
十、常见陷阱
strip("abc") 不是去掉子串 ,而是去掉两端属于 a/b/c 的任意字符。去子串用 removeprefix/removesuffix。
in 判断子串包含 ,别写成 s.find(x) != -1:if "py" in s: 更 Pythonic。
不要在循环里 += 拼字符串 ,用 list.append + "".join。
isdigit() 对负号和小数点返回 False :"-3".isdigit() 是 False,判断”是否是数字”最好写 try/except int()。
Windows 路径中的反斜杠 :"C:\new\test.py" 会把 \n 解析成换行。用 raw string r"..." 最省心。
多行 f-string 里的花括号 :想输出真正的 {,要写 {{`;输出 `}` 写 `}}。
split() 无参数与有参数不同 :无参数按任意连续空白切且忽略首尾,split(" ") 是严格按单空格切且保留空串。
1 2 " a b " .split() " a b " .split(" " )
十一、小结与延伸阅读
字符串不可变,索引切片都返回新字符串;
用 f-string 做格式化;
用 join 不用 += 做拼接;
熟悉 strip / split / replace / find / startswith / endswith 这几个高频方法;
中文场景注意 encode/decode,默认用 UTF-8;
Windows 路径记得 r"...";
需要更强查找/替换能力时上正则。
延伸阅读:
下一篇 输入输出与格式化字符串 我们要让程序真正开口和用户对话。