一、开篇:字符串是一串带编号的字符
想象一下酒店的房间走廊——每个房间门上都贴着一个编号,第一个房间是0号,第二个是1号,以此类推。python中的字符串就像这个走廊,每个字符是一个房间,而索引就是房间号。
在python中,操作字符串的"任意部分"——提取子串、反转字符串、隔位取值——这些操作通过索引和切片来实现。这两个操作是python字符串处理中最常用、最核心的技能。一旦掌握它们,你处理文本的能力将提升一个档次。
二、索引基础:单个字符的访问
2.1 正索引:从左往右,从0开始
python的索引从0开始——这是计算机世界的通用惯例:
text = 'python' # 索引: p y t h o n # 正索引: 0 1 2 3 4 5 # 负索引:-6 -5 -4 -3 -2 -1 print(text[0]) # p(第一个字符) print(text[1]) # y print(text[2]) # t print(text[5]) # n(最后一个字符) print(text[6]) # indexerror: string index out of range
"从0开始"对初学者来说可能不习惯,但这是几乎所有编程语言的传统。记住:第n个字符的索引是n-1。
2.2 负索引:从右往左,从-1开始
python的负索引是一个非常有用的特性,让你可以从末尾往前数:
text = 'python' print(text[-1]) # n(倒数第一个,即最后一个) print(text[-2]) # o(倒数第二个) print(text[-3]) # h(倒数第三个) print(text[-6]) # p(倒数第六个,即第一个) print(text[-7]) # indexerror: string index out of range
负索引的实际应用:
# 获取文件扩展名(不用split的替代方案)
filename = 'report_2024.pdf'
extension = filename[filename.rfind('.'):]
print(extension) # .pdf
# 检查字符串后缀
def has_extension(filename, ext):
"""检查文件是否有特定扩展名"""
return filename[-len(ext):] == ext
print(has_extension('data.csv', '.csv')) # true
print(has_extension('data.json', '.csv')) # false
# 获取最后一个字符(比如判断路径末尾是否有/)
path = '/home/user/documents/'
if path[-1] == '/':
print('路径以/结尾')
2.3 索引越界
访问超出范围的索引会触发 indexerror:
text = 'hello'
try:
print(text[10])
except indexerror as e:
print(f'索引越界:{e}')
print(f'字符串长度是{len(text)},有效索引是-{len(text)}到{len(text)-1}')
# 安全获取指定位置的字符
def safe_get_char(text, index):
"""安全地获取指定索引的字符,越界返回none"""
if -len(text) <= index < len(text):
return text[index]
return none
text = 'python'
print(safe_get_char(text, 0)) # p
print(safe_get_char(text, 100)) # none
三、切片基础:获取一段子串
3.1 切片语法:text[start:stop:step]
切片的基本语法是 [start:stop:step]:
start:起始索引(包含,即从这个位置开始取)stop:结束索引(不包含,即取到这个位置之前)step:步长(默认是1)
text = 'python编程' # 基本切片 print(text[0:6]) # 'python'(索引0到5,不包含6) print(text[6:8]) # '编程'(索引6、7) # 图解:text = 'p y t h o n 编 程' # 索引: 0 1 2 3 4 5 6 7 # text[0:6] 取索引0,1,2,3,4,5 → 'python' # text[6:8] 取索引6,7 → '编程'
切片的"不包含stop"规则是最容易让新手出错的地方。记住一个记忆技巧:text[a:b] 返回的字符个数正好是 b - a。
3.2 省略start或stop
text = 'python' # 省略start:从开头开始取 print(text[:3]) # 'pyt'(等价于text[0:3]) # 省略stop:取到末尾 print(text[3:]) # 'hon'(等价于text[3:len(text)]) # 两个都省略:取整个字符串(浅拷贝) print(text[:]) # 'python' # 负索引在切片中 print(text[-3:]) # 'hon'(取最后3个字符) print(text[:-2]) # 'pyth'(去掉最后2个字符)
实用案例:
# 去除文件扩展名
filename = 'document.txt'
name_without_ext = filename[:-4] # 去掉.txt
print(name_without_ext) # document
# 更通用的方式
def get_filename_without_extension(filename):
"""获取不含扩展名的文件名"""
dot_index = filename.rfind('.')
if dot_index == -1:
return filename
return filename[:dot_index]
# 获取域名
url = 'https://www.example.com/path/page.html'
domain = url[url.index('//') + 2:url.index('/', url.index('//') + 2)]
print(domain) # www.example.com
3.3 带步长的切片
text = 'python编程' # 步长为2,隔一个取一个 print(text[::2]) # 'pto编'(取索引0,2,4,6) # 步长为3 print(text[::3]) # 'ph程'(取索引0,3,6) # 从索引1开始,步长为2 print(text[1::2]) # 'yhn程'(取索引1,3,5,7) # 负步长——反向取 print(text[::-1]) # '程编nohtyp'(字符串反转!) print(text[::-2]) # '程nhy'(反向隔一个取一个)
text[::-1] 是python中最简洁的字符串反转方式。这在判断回文串时特别有用:
def is_palindrome(text):
"""判断字符串是否是回文"""
clean_text = text.lower().replace(' ', '')
return clean_text == clean_text[::-1]
print(is_palindrome('racecar')) # true
print(is_palindrome('a man a plan a canal panama')) # true
print(is_palindrome('hello')) # false
3.4 切片图解
字符串: p y t h o n 编 程 正索引: 0 1 2 3 4 5 6 7 负索引:-8 -7 -6 -5 -4 -3 -2 -1 text[0:4] = 'pyth' (取0,1,2,3) text[4:] = 'on编程' (取4,5,6,7) text[:4] = 'pyth' (取0,1,2,3) text[2:6] = 'thon' (取2,3,4,5) text[-3:] = 'n编程' (取-3,-2,-1 → 5,6,7) text[1:-1] = 'ython编' (取1到-2 → 1,2,3,4,5,6) text[::2] = 'pto编' (0,2,4,6) text[::-1] = '程编nohtyp' (取-1,-2,...,-8)
四、切片的高级用法
4.1 越界切片不会报错
和索引不同,切片的start或stop超出范围不会报错——python会自动调整到有效范围:
text = 'python' # 索引越界会报错 # print(text[100]) # indexerror! # 切片越界不会报错——python自动处理 print(text[0:100]) # 'python'(stop被截断为len(text)) print(text[100:]) # ''(start超出范围,返回空字符串) print(text[-100:3]) # 'pyt'(start被截断为0)
这个特性让切片用起来比索引"宽容"得多——你不需要担心越界问题。
4.2 使用切片删除或替换部分字符串
text = 'hello, world!' # "删除"前6个字符(实际是创建新字符串) new_text = text[7:] print(new_text) # world! # "替换"中间的一部分 # 把'world'替换为'python' text = 'hello, world!' new_text = text[:7] + 'python' + text[12:] print(new_text) # hello, python! # 插入内容 text = 'helloworld' new_text = text[:5] + ' ' + text[5:] print(new_text) # hello world # 删除最后一个字符 text = 'hello!' new_text = text[:-1] print(new_text) # hello
4.3 使用切片进行文本清理
def remove_whitespace(text):
"""去除字符串首尾的空白字符"""
start = 0
end = len(text)
while start < end and text[start].isspace():
start += 1
while end > start and text[end - 1].isspace():
end -= 1
return text[start:end]
# 当然,实际开发中用strip()即可
# 这个例子只是演示如何用切片实现类似功能
print(repr(remove_whitespace(' hello '))) # 'hello'
def truncate(text, max_length, suffix='...'):
"""截断长字符串,加上后缀"""
if len(text) <= max_length:
return text
return text[:max_length - len(suffix)] + suffix
print(truncate('这是一段很长的文本内容需要被截断', 10))
# 这是一段很长...
4.4 用切片实现文本分页
def paginate_text(text, page_size):
"""将文本按指定大小分页"""
return [text[i:i + page_size] for i in range(0, len(text), page_size)]
long_text = 'python编程语言是一门强大而优雅的语言,适合各种开发场景。'
pages = paginate_text(long_text, 10)
for i, page in enumerate(pages, 1):
print(f'第{i}页: {page}')
五、切片的性能特性
5.1 切片会创建新字符串
text = 'python' slice_text = text[0:3] print(id(text)) # 比如 14073512345 print(id(slice_text)) # 比如 14073567890(不同的id) # 切片创建了新字符串,不是引用原字符串的一部分
5.2 小字符串切片的优化
# 对于非常小的字符串,重复切片影响不大 # 但对于大字符串(如文件内容),要注意 # 如果只需要首尾等特定部分,用索引而不是切片 text = 'hello' # text[0:1] # 获取第一个字符,但返回字符串'h'(不是字符) first_char = text[0] # 获取第一个字符,返回字符'h'(效率略高)
5.3 大文本切片建议
# 处理大文本时,如果频繁切片会产生大量临时字符串对象
# 建议:对需要多次使用的切片结果,存到变量里
# ❌ 低效
def process_text_v1(text):
for i in range(1000):
part = text[i:i+100]
process(part)
# ✅ 高效
def process_text_v2(text):
for i in range(0, len(text), 100):
part = text[i:i+100] # 每个块只切片一次
process(part)
六、切片操作的实际应用
6.1 提取日期各部分
date_str = '2024-05-30'
year = date_str[:4]
month = date_str[5:7]
day = date_str[8:10]
print(f'{year}年{month}月{day}日') # 2024年05月30日
6.2 解析固定格式的文本
# 假设有固定格式的日志:8位日期 + 6位时间 + 等级(4位) + 消息
log_entry = '20240530143000info用户登录成功'
timestamp = log_entry[:14] # '20240530143000'
level = log_entry[14:18] # 'info'
message = log_entry[18:] # '用户登录成功'
print(f'时间: {timestamp}')
print(f'等级: {level}')
print(f'消息: {message}')
6.3 生成密码掩码
def mask_string(text, visible_chars=4, mask_char='*'):
"""将字符串的一部分隐藏"""
if len(text) <= visible_chars:
return text
visible_part = text[-visible_chars:]
masked_part = mask_char * (len(text) - visible_chars)
return masked_part + visible_part
# 手机号脱敏
phone = '13812345678'
print(mask_string(phone, 4)) # *******5678
# 身份证号脱敏
id_card = '110101199001011234'
print(mask_string(id_card, 4)) # **************1234
# 银行卡号脱敏
bank_card = '6222021234567890'
print(mask_string(bank_card, 4)) # ************7890
6.4 字符串轮转
def rotate_string(text, n):
"""将字符串向左轮转n位"""
if not text:
return text
n %= len(text) # 处理n大于字符串长度的情况
return text[n:] + text[:n]
text = 'python'
print(rotate_string(text, 1)) # ythonp
print(rotate_string(text, 2)) # thonpy
print(rotate_string(text, -1)) # npytho(负数右转)
七、切片的常见错误
7.1 搞混索引和切片
text = 'hello' # 索引返回单个字符 print(text[0]) # 'h'(str类型,单个字符) print(type(text[0])) # <class 'str'> # 切片返回字符串 print(text[0:1]) # 'h'(str类型,但是用切片取的) print(type(text[0:1])) # <class 'str'> # 注意两者的区别 # text[0] vs text[0:1] # text[1] 如果超出范围会indexerror # text[0:1] 如果超出范围返回空字符串''
7.2 步长符号搞反
text = 'python' # 正向步长:start必须小于stop print(text[0:4:1]) # 'pyth'(ok:0 < 4) print(text[4:0:1]) # ''(start > stop且step为正,返回空) # 反向步长:start必须大于stop print(text[4:0:-1]) # 'ohty'(ok:4 > 0,从索引4向索引0走) print(text[0:4:-1]) # ''(start < stop且step为负,返回空) # 反向取全部 print(text[::-1]) # 'nohtyp'
八、本篇小结
索引和切片是python字符串操作的核心技能。今天的内容:
- 索引从0开始:
text[0]是第一个字符,text[-1]是最后一个 - 切片语法:
[start:stop:step],包含start,不包含stop - 省略规则:
text[:3]从头取,text[3:]取到末尾,text[:]取全部 - 负步长反转:
text[::-1]是最简洁的字符串反转 - 切片不报错:越界切片自动调整,比索引宽容
- 性能注意:大文本频繁切片会产生大量临时对象
索引和切片不仅在字符串中用,列表、元组也支持相同的操作。掌握了这一套,你就能在所有序列类型中游刃有余。
以上就是python字符串索引与切片操作的完全指南的详细内容,更多关于python字符串索引与切片操作的资料请关注代码网其它相关文章!
发表评论