從字串右側搜尋子字串最後出現位置,並在找不到時拋出例外而非回傳 -1,這正是 rindex() 的設計用途。它與 rfind() 行為幾乎相同,唯一差異在錯誤處理策略。本文詳細說明語法、參數、例外處理、與 rfind/index 比較及實戰應用。
str.rindex(sub[, start[, end]])
ValueError: substring not found。rfind,索引從左向右計算(0 起始),僅回傳最右匹配位置。#!/usr/bin/python3
str1 = "this is string example....wow!!!"
str2 = "is"
# 範例 1:基本用法
print(str1.rindex(str2)) # 5(最後一個 "is")
print(str1.index(str2)) # 2(第一個 "is")
# 範例 2:指定範圍
print(str1.rindex(str2, 0, 10)) # 5
# print(str1.rindex(str2, 10, 0)) # ValueError(空範圍)
# 範例 3:找不到拋出例外
try:
print(str1.rindex("xyz"))
except ValueError as e:
print(f"找不到: {e}") # 找不到: substring not found
# 範例 4:空字串特殊行為
print(str1.rindex("")) # len(str1) = 35
print(str1.index("")) # 0
| 方法 | 搜尋方向 | 找到回傳 | 找不到行為 | 適用場景 |
|---|---|---|---|---|
| find() | 左→右(首次) | 索引 | 回傳 -1 | 不確定存在、流程控制 |
| rfind() | 右→左(末次) | 索引 | 回傳 -1 | 不確定存在、從右找 |
| index() | 左→右(首次) | 索引 | 拋 ValueError | 確定存在、視缺失為錯誤 |
| rindex() | 右→左(末次) | 索引 | 拋 ValueError | 確定存在、從右找 |
def find_last_occurrence(text, target):
try:
return text.rindex(target)
except ValueError:
return -1 # 或 None、拋出自訂例外
print(find_last_occurrence("abcabc", "b")) # 4
print(find_last_occurrence("abcabc", "x")) # -1
def find_last_occurrence_lbyl(text, target):
if target in text:
return text.rindex(target)
return -1
# 注意:'in' 會掃描一次,rindex 再掃描一次,效能較差
class SubstringNotFoundError(ValueError):
def __init__(self, text, target, start=0, end=None):
self.text = text
self.target = target
self.start = start
self.end = end
super().__init__(f"Substring '{target}' not found in text[{start}:{end}]")
def safe_rindex(text, target, start=0, end=None):
try:
return text.rindex(target, start, end)
except ValueError:
raise SubstringNotFoundError(text, target, start, end)
# 使用
try:
pos = safe_rindex("hello world", "x")
except SubstringNotFoundError as e:
print(f"錯誤: {e}, 文本長度: {len(e.text)}")
def get_filename_and_ext(path):
"""假設 path 為合法路徑,必含檔名"""
# 最後一個斜線
slash_idx = path.rindex("/")
filename = path[slash_idx + 1:]
# 最後一個點(副檔名分隔)
# 若無點,rindex 拋出例外 → 視為格式錯誤
dot_idx = filename.rindex(".")
name = filename[:dot_idx]
ext = filename[dot_idx + 1:]
return name, ext
# 正確
print(get_filename_and_ext("/home/user/file.txt")) # ('file', 'txt')
# 錯誤:無副檔名
try:
get_filename_and_ext("/home/user/README")
except ValueError:
print("路徑缺少副檔名")
def parse_http_request_line(line):
"""解析 'GET /path HTTP/1.1'"""
# 最後空格前為版本
last_space = line.rindex(" ")
version = line[last_space + 1:]
# 第一空格後為路徑起始
first_space = line.index(" ")
method = line[:first_space]
path = line[first_space + 1:last_space]
return method, path, version
print(parse_http_request_line("GET /api/users HTTP/1.1"))
# ('GET', '/api/users', 'HTTP/1.1')
def extract_between_last(s, left_delim, right_delim):
"""提取最後一對分隔符之間的內容"""
try:
left_idx = s.rindex(left_delim)
right_idx = s.rindex(right_delim, left_idx + len(left_delim))
return s[left_idx + len(left_delim):right_idx]
except ValueError:
return None
log = "[START] Task A [END] [START] Task B [END]"
print(extract_between_last(log, "[START] ", " [END]")) # Task B
import re
def rindex_regex(pattern, string, start=0, end=None):
"""正則搜尋最後匹配,找不到拋出 ValueError"""
if end is None:
end = len(string)
matches = list(re.finditer(pattern, string[start:end]))
if not matches:
raise ValueError(f"Pattern '{pattern}' not found")
last = matches[-1]
return (last.start() + start, last.end() + start)
# 使用
try:
print(rindex_regex(r"error_\d+", "error_1 error_2 error_3")) # (16, 24)
except ValueError as e:
print(e)
rindex() 是「確定存在、從右找、缺失即錯誤」場景的標準工具。核心價值:**以例外明確表達「不應發生」的情況**,避免 -1 混入索引運算導致隱蔽 Bug。搭配 try/except(EAFP)或 in 檢查(LBYL)使用。路徑解析、協議分析、固定格式提取是典型應用。記住:索引仍從左計算,start/end 遵循切片語意支援負索引。