Python3 字符串操作详解:从基础到高级技巧
Python 字符串:处理文本的这几十种方法,其实常用的就那些
写 Python 代码,字符串操作避不开。解析日志、处理用户输入、拼 SQL、格式化输出——天天都在跟文本打交道。
Python 的字符串方法多,但常用的就那么十几个。
字符串是什么,记住两点就够了
- 不可变
s = "hello"
# s[0] = "H" # 报错!不能直接改
# 想改?创建新字符串
s = "H" + s[1:] # "Hello"
字符串一旦创建就不能改,所有”修改”操作都是创建新字符串。记住这点,写代码的时候就不会困惑了。
- 序列,可以索引和切片
s = "Python"
s[0] # "P",从0开始
s[-1] # "n",倒数第一个
s[1:4] # "yth",从索引1到3,左闭右开
s[::-1] # "nohtyP",反转
切片是字符串最常用的操作之一,记住 [start:stop:step] 左闭右开就行。
查和找:在一段文本里找东西
判断开头结尾:
url = "https://example.com"
url.startswith("https") # True
url.endswith(".com") # True
找子串的位置:
text = "hello world, hello python"
text.find("world") # 6,返回第一次出现的位置
text.find("java") # -1,找不到返回-1
text.rfind("hello") # 13,从右边找
# 如果确定存在,用 index(找不到会报错)
text.index("world") # 6
日常用 find 就够了,返回 -1 表示没有。index 会抛异常,除非你很确定那个子串一定存在。
统计出现次数:
text.count("hello") # 2
text.count("o") # 4
检查是否包含某个子串:
if "world" in text:
print("找到了")
if "java" not in text:
print("没有")
in 和 not in 比 find() != -1 更直观,推荐用这个。
改:替换、大小写、去空格
替换:
text = "hello world, hello python"
text.replace("hello", "hi") # "hi world, hi python"
text.replace("hello", "hi", 1) # "hi world, hello python",只替换第一个
大小写转换:
s = "Hello World"
s.upper() # "HELLO WORLD"
s.lower() # "hello world"
s.capitalize() # "Hello world",首字母大写其余小写
s.title() # "Hello World",每个单词首字母大写
去空格和换行:
s = " \t hello \n "
s.strip() # "hello",去掉两端空白
s.lstrip() # "hello \n ",去掉左边
s.rstrip() # " \t hello",去掉右边
# 去掉指定字符
"***hello***".strip("*") # "hello"
处理用户输入的时候,strip() 几乎是必用的——去掉用户不小心敲的空格。
拆和拼:字符串 ↔ 列表
拆:字符串变列表
s = "apple,banana,orange"
s.split(",") # ['apple', 'banana', 'orange']
# 默认按任意空白拆分(多个空格也OK)
"hello world".split() # ['hello', 'world']
# 控制拆分次数
"a,b,c,d".split(",", 2) # ['a', 'b', 'c,d']
# 按换行拆
"a\nb\nc".splitlines() # ['a', 'b', 'c']
拼:列表变字符串
fruits = ['apple', 'banana', 'orange']
",".join(fruits) # "apple,banana,orange"
" ".join(fruits) # "apple banana orange"
拼大量字符串的时候,千万别用 +=:
# 错误: 慢,每次拼接都创建新字符串
result = ""
for i in range(10000):
result += str(i)
# 优化: 快,用列表收集最后 join
parts = []
for i in range(10000):
parts.append(str(i))
result = "".join(parts)
join 比 += 快 10 到 50 倍,数据量大的时候差距更明显。
格式化:把变量放进字符串
三种方式,我建议直接用第三种。
方式1:% 格式化(老式,不推荐)
"姓名:%s,年龄:%d" % ("张三", 25)
方式2:format()(还行,但不够简洁)
"姓名:{},年龄:{}".format("张三", 25)
方式3:f-string(Python 3.6+,推荐)
name = "张三"
age = 25
f"姓名:{name},年龄:{age}" # 最直观,最快
# 还可以放表达式
f"明年年龄:{age + 1}"
# 数字格式化
f"价格:{price:.2f}" # 保留两位小数
f"百分比:{rate:.1%}" # 转成百分比
# 对齐
f"{"左":<10}" # 左对齐
f"{"右":>10}" # 右对齐
f"{"中":^10}" # 居中
f-string 比前两种都快,而且代码最干净。能用 f-string 就别用前面两种了。
判断:检查字符串是什么类型
"123".isdigit() # True,全是数字
"abc".isalpha() # True,全是字母
"abc123".isalnum() # True,全是字母或数字
" ".isspace() # True,全是空白
"Hello".islower() # False
"HELLO".isupper() # True
这些方法在校验用户输入的时候很好用:
phone = input("请输入手机号:")
if not phone.isdigit():
print("手机号只能包含数字")
正则表达式:复杂匹配的终极武器
字符串方法只能做简单匹配,遇到复杂需求就得用正则了。
提取手机号:
import re
text = "我的电话是 13812345678"
match = re.search(r"1[3-9]\d{9}", text)
if match:
print(match.group()) # 13812345678
提取所有邮箱:
text = "联系我:test@example.com 或 admin@test.com"
emails = re.findall(r"\w+@\w+\.\w+", text)
# ['test@example.com', 'admin@test.com']
替换敏感信息:
re.sub(r"1[3-9]\d{9}", "***", text)
常用正则写法速查:
| 需求 | 正则 |
|---|---|
| 手机号 | 1[3-9]\d{9} |
| 邮箱 | \w+@\w+\.\w+ |
| 数字 | \d+ |
| 中文 | [\u4e00-\u9fa5]+ |
| URL | https?://[^\s]+ |
匹配中文的时候 \w 在 Python 里默认只匹配 ASCII,要匹配中文得用 [\u4e00-\u9fa5]。