字符串是编程中最常用的数据类型之一,无论是用户输入、文件内容还是网络数据,都离不开字符串处理。本章将系统学习字符串的表示、转换、格式化以及常见操作方法,最后通过一个完整的单词统计案例加深理解。
一、字符串的表示方式
Python 中有三种表示字符串的方式:普通字符串、原始字符串和长字符串。
# 1.1 普通字符串与转义字符
普通字符串使用单引号(')或双引号(")括起来。例如:'Hello' 或 "World"。
如果字符串中需要包含特殊字符(如换行、制表符、引号等),则需要使用反斜杠(\)进行转义。
常用转义符:
- \t:水平制表符(Tab)
- \n:换行符
- \r:回车符
- \":双引号
- \':单引号
- \\:反斜线本身
示例:
python
print("Hello\nWorld") # 输出两行:Hello 和 World
print('She said, "Hi!"') # 双引号无需转义,因为外层是单引号
print('It\'s a book') # 单引号需要转义
# 1.2 原始字符串
原始字符串以r 或 R 开头,其中的反斜杠不再表示转义,而是普通字符。常用于文件路径、正则表达式等场景。
示例:
python
# 普通字符串:\n 被解释为换行
path = "C:\new\test.txt" # 实际会包含换行符,出错
# 原始字符串:原样输出
raw_path = r"C:\new\test.txt"
print(raw_path) # 输出 C:\new\test.txt
对比普通字符串中的\n 和原始字符串中的 \n:
python
normal = 'Hello\nworld' # 换行
raw = r'Hello\nworld' # 原样显示 Hello\nworld
print(normal)
print(raw)
# 1.3 长字符串
长字符串使用三个单引号''' 或三个双引号 """ 括起来,可以跨越多行,保留其中的换行和缩进。
示例:
python
long_text = """
这是第一行
这是第二行
这是带有缩进的第三行
"""
print(long_text)
长字符串常用于文档注释(docstring)或保存大段文本。
二、字符串与数字的相互转换
# 2.1 将字符串转换为数字
使用int() 和 float() 函数可以将数字字符串转换为整数或浮点数。如果字符串内容不是合法数字,会引发异常。
示例:
python
s1 = "85"
s2 = "92.5"
score_int = int(s1) # 85
score_float = float(s2) # 92.5
print(score_int + 10) # 95
# 错误示例:int("abc") 会报错
# 2.2 将数字转换为字符串
使用str() 函数可以将任意类型的数据转换为字符串,常用于拼接输出。
示例:
python
age = 18
message = "我今年" + str(age) + "岁"
print(message) # 我今年18岁
三、格式化字符串
使用字符串的format() 方法可以将表达式的计算结果插入字符串中的占位符位置。
# 3.1 占位符
占位符使用花括号{} 表示。可以有三种形式:
- 默认占位符:{},按顺序填充
- 参数序号占位符:{0}、{1},指定位置
- 参数名占位符:{name},通过关键字参数赋值
示例:
python
# 默认占位符
s1 = "我叫{},今年{}岁".format("小明", 18)
# 序号占位符(可重复使用)
s2 = "{0}的成绩是{1}分,{0}很优秀".format("张三", 95)
# 参数名占位符
s3 = "我是{name},来自{city}".format(name="李四", city="北京")
print(s1) # 我叫小明,今年18岁
print(s2) # 张三的成绩是95分,张三很优秀
print(s3) # 我是李四,来自北京
# 3.2 格式控制符
在占位符中可以添加格式控制符,指定输出的类型、宽度、精度等。语法为:{序号:格式符}
常用格式符:
- s:字符串
- d:十进制整数
- f:浮点数(默认6位小数)
- .2f:保留两位小数
- e:科学计数法
- o:八进制
- x:十六进制
示例:
python
pi = 3.1415926
print("圆周率约等于{:.2f}".format(pi)) # 圆周率约等于3.14
print("二进制:{:b}".format(10)) # 二进制:1010
print("百分比:{:.0%}".format(0.875)) # 百分比:88%
四、操作字符串
Python 字符串提供了丰富的方法来查找、替换、分割等。
# 4.1 字符串查找
find(sub[, start[, end]]):在指定范围内查找子字符串,返回最左端索引;如果未找到,返回 -1。
示例:
python
text = "the best of time"
pos = text.find("best")
print(pos) # 4("best" 首字母 b 的索引)
pos2 = text.find("good")
print(pos2) # -1
# 4.2 字符串替换
replace(old, new[, count]):用 new 替换 old,count 指定替换次数(默认全部替换)。
示例:
python
quote = "it was the best of time it was the worst of times"
new_quote = quote.replace("time", "day")
print(new_quote)
# 输出:it was the best of day it was the worst of days
# 4.3 字符串分割
split(sep=None, maxsplit=-1):以 sep 为分隔符分割字符串,返回列表。默认按任意空白字符(空格、换行、制表符)分割。
示例:
python
sentence = "apple banana cherry"
words = sentence.split()
print(words) # ['apple', 'banana', 'cherry']
data = "张三,李四,王五"
names = data.split(",")
print(names) # ['张三', '李四', '王五']
五、综合案例:统计文章中的单词频率
下面是一个完整的案例,结合了字符串的替换、分割、列表操作和字典,用于统计一段文本中每个单词出现的次数。
**代码文件:ch7_5.py**
python
# coding=utf-8
# 代码文件:ch07/ch7_5.py
# 一篇文章文本
wordstring = '''
it was the best of time it was the worst of the times.
it was the age of wisdom it was the age of foolishness.
'''
# 将标点符号替换(删除句号)
wordstring = wordstring.replace('.', '')
# 分割单词(默认按空白字符分割)
wordlist = wordstring.split()
# 此时 wordlist 包含重复单词,例如 ['it', 'was', 'the', 'best', ...]
wordfreq = []
for w in wordlist:
# 统计每个单词出现的次数
wordfreq.append(wordlist.count(w))
# 将单词列表和频率列表打包成字典
d = dict(zip(wordlist, wordfreq))
print(d)
**运行结果**(输出顺序可能不同):
{'it': 4, 'was': 4, 'the': 4, 'best': 1, 'of': 4, 'time': 2, 'worst': 1, 'times': 1, 'age': 2, 'wisdom': 1, 'foolishness': 1}
**代码解析**:
1. **原始文本**:包含多行、首尾空格和句点。
2. **.replace('.', '')**:删除所有句号,避免句点干扰单词识别。
3. **.split()**:按空白字符(空格、换行、制表符)将文本切分成单词列表,同时自动丢弃空白。注意 'times.' 变成了 'times'。
4. **统计频率**:循环遍历每个单词,使用 list.count(w) 统计它在整个列表中出现的次数。这种方法虽然直观,但效率不高(每次 count 都会遍历整个列表),适合小规模文本。
5. **zip(wordlist, wordfreq)**:将两个列表配对成 (单词, 次数) 的元组序列。由于 wordlist 中单词重复,相同的键会覆盖,但所有相同单词的频率值是一样的,所以最终字典每个单词只出现一次,且频率正确。
# 高效写法详解(一次遍历完成统计)
对于较大的文本,上述方法效率较低。下面给出一种更高效的写法,只需遍历列表一次即可统计完所有单词的出现次数。
**高效版本代码**:
python
wordcount = {}
for w in wordlist:
wordcount[w] = wordcount.get(w, 0) + 1
print(wordcount)
**逐步解析**:
假设当前wordlist = ['it', 'was', 'the', 'best', 'of', 'time', 'it', ...]。
- 第一次循环,w = 'it':
此时wordcount 是空字典 {}。
wordcount.get('it', 0) 的意思是:如果字典中有键 'it',则返回它的值;否则返回 0。因为字典为空,返回 0。
然后0 + 1 = 1,再执行 wordcount['it'] = 1,字典变为 {'it': 1}。
- 第二次循环,w = 'was':
'was' 不在字典中,get 返回 0,加 1 后赋值,字典变为 {'it': 1, 'was': 1}。
- 第三次循环,w = 'the':
类似,字典变为{'it': 1, 'was': 1, 'the': 1}。
- 第四次循环,w = 'best':
字典变为{'it': 1, 'was': 1, 'the': 1, 'best': 1}。
- 第五次循环,w = 'of':
字典变为{'it': 1, 'was': 1, 'the': 1, 'best': 1, 'of': 1}。
- 第六次循环,w = 'time':
字典增加'time': 1。
- 当后面再次遇到 w = 'it' 时:
此时字典中已有'it' 键,且值为 1。
wordcount.get('it', 0) 返回 1(因为键存在,不再使用第二个参数)。
然后1 + 1 = 2,执行 wordcount['it'] = 2,将 'it' 的计数更新为 2。
如此继续,最终每个单词的计数都会被正确累加。
**核心理解**:
字典.get(键, 默认值) 是一个安全取值的方法——如果键存在,返回其值;如果键不存在,返回默认值(这里默认值为 0)。然后加 1 再放回字典,实现了“计数累加”的效果。整个过程只遍历列表一次,时间复杂度为 O(n),远高于原方法的 O(n²)。
**完整运行示例**(短列表):
python
wordlist = ['it', 'was', 'the', 'it']
wordcount = {}
for w in wordlist:
wordcount[w] = wordcount.get(w, 0) + 1
print(wordcount) # {'it': 2, 'was': 1, 'the': 1}
如果还不理解,可以手动模拟一下循环过程:
- 第1次:w='it',wordcount={},get返回0,计算得1,赋值后 wordcount={'it':1}
- 第2次:w='was',wordcount={'it':1},get('was',0)返回0,得1,赋值后 wordcount={'it':1, 'was':1}
- 第3次:w='the',wordcount={'it':1, 'was':1},get('the',0)返回0,得1,赋值后 wordcount={'it':1, 'was':1, 'the':1}
- 第4次:w='it',wordcount={'it':1, 'was':1, 'the':1},get('it',0)返回1,得2,赋值后 wordcount={'it':2, 'was':1, 'the':1}
通过这个逐步推演,就能清楚看到每个单词的计数如何累加。
六、总结
- **字符串表示**:普通字符串(可含转义)、原始字符串(r前缀,不转义)、长字符串(三引号,可跨行)。
- **类型转换**:int()、float() 转数字,str() 转字符串。
- **格式化**:format() 方法配合占位符 {},可指定格式控制符(如 :.2f)。
- **常用操作**:
- 查找:find() 返回索引或 -1。
- 替换:replace() 生成新字符串。
- 分割:split() 返回列表。
- **单词统计案例**:综合运用替换、分割、列表和字典,实现简单的文本分析。高效写法利用了 dict.get() 方法,一次遍历完成计数。
下一章我们将学习函数—— 将重复代码封装起来的高效工具。