文字列が特定の文字で始まるか、または終わるかを判定する処理は、データのフィルタリングやバリデーションで頻出します。
Pythonにはこの目的に特化したstartswith
とendswith
があり、直感的で安全に判定できます。
本記事では基本から応用、実用例、注意点まで段階的に解説します。
Pythonのstartswithとendswithの基本
startswithの基本構文と使い方
str.startswith(prefix[, start[, end]])
は、文字列が指定したprefix
で始まっているかを真偽値で返します。
start
とend
は検索範囲(スライス)を指定する任意引数です。
# 基本的なstartswithの使い方
s = "Hello, world!"
print(s.startswith("He")) # "He"で始まるか
print(s.startswith("he")) # 大文字小文字は区別される
print(s.startswith("Hello,")) # 複数文字の接頭辞もOK
True
False
True
先頭ではなく、途中からの判定
start
やend
を指定すると、文字列の一部範囲に対して「その範囲の先頭がprefixか」を判定できます。
end
はスライス同様に末尾は含まれません。
s = "2025-08-31"
# s[5:7] == "08" の先頭が "0" か? → True
print(s.startswith("0", 5, 7))
# s[0:4] == "2025" の先頭が "2025" か? → True
print(s.startswith("2025", 0, 4))
# 負のインデックスも使えます
# s[-2:] == "31" の先頭が "3" か? → True
print(s.startswith("3", -2))
True
True
True
endswithの基本構文と使い方
str.endswith(suffix[, start[, end]])
は、文字列が指定したsuffix
で終わっているかを真偽値で返します。
start
とend
の解釈はstartswith
と同様です。
# 基本的なendswithの使い方
s = "report_final.pdf"
print(s.endswith(".pdf")) # ".pdf"で終わるか
print(s.endswith("PDF")) # 大文字小文字は区別される
True
False
一部範囲での末尾判定
部分範囲の「末尾がsuffixか」を判定できます。
s = "abc-12345-xyz"
# s[4:9] == "12345" の末尾が "45" か? → True
print(s.endswith("45", 4, 9))
# s[:-4] == "abc-12345" の末尾が "345" か? → True
print(s.endswith("345", 0, -4))
True
True
if文での使い方と真偽値
startswith
とendswith
は真偽値(True/False)を返すため、そのままif
条件に使えます。
filename = "data_2025.csv"
if filename.endswith(".csv"):
print("CSVファイルです。")
else:
print("CSVファイルではありません。")
url = "https://example.com"
if url.startswith("https://"):
print("HTTPSです。")
CSVファイルです。
HTTPSです。
startswithとendswithの応用テクニック
複数候補を一度に判定する
prefix
やsuffix
にタプルを渡すと、いずれかに一致すればTrueになります。
拡張子やプロトコルの判定に便利です。
# 画像拡張子のいずれかで終わるかを判定
name = "picture.JPEG"
print(name.lower().endswith((".jpg", ".jpeg", ".png", ".gif")))
# URLのプロトコルがhttpまたはhttpsかを判定
url = "http://example.org"
print(url.startswith(("http://", "https://")))
True
True
注意: リスト[".jpg", ".png"]
は直接渡せません。
タプル(".jpg", ".png")
を使います(後述の落とし穴参照)。
startとend引数で部分範囲を指定
ログの行頭タイムスタンプやファイル名の特定位置のパターンなど、文字列全体ではなく一部範囲を対象にできます。
line = "[2025-08-31 12:00:00] INFO: Start"
# 先頭の角括弧の直後(1文字目)から10文字分が"2025-08-31"で始まるか
print(line.startswith("2025-08-31", 1, 11))
# ファイル名の末尾から16文字手前までの範囲の末尾が"backup"か
fname = "db_backup_20250831.tar.gz"
print(fname.endswith("backup", 0, -16)) # "db_backup" の末尾が "backup"
True
True
end
はスライス同様に「排他的(その位置は含まれない)」であることを覚えておくと混乱しません。
casefoldで大文字小文字を無視して判定
startswith
/endswith
はデフォルトで大文字小文字を区別します。
大小無視での判定は、比較対象をあらかじめ同じ正規化に揃えます。
国際化を考慮するならstr.casefold()
が推奨です。
# 大文字小文字を無視した先頭・末尾判定
s = "Straße.TXT"
prefix = "STRAS" # ドイツ語 ß を含むケースの例
suffix = ".txt"
# どちらもcasefoldして比較する
print(s.casefold().startswith(prefix.casefold()))
print(s.casefold().endswith(suffix.casefold()))
True
True
str.lower()
でも英語圏では事足りることが多いですが、”ß”→”ss”のような言語特有の変換を含む場合はcasefold
がより適切です。
実用例で学ぶ文字列の始まりと終わりの判定
ファイル拡張子をendswithで判定
拡張子によって処理を分けるのは定番です。
複数の拡張子をまとめて扱う例を示します。
files = [
"report.pdf", "data.csv", "archive.tar.gz", "image.PNG", "README", "script.Py"
]
for f in files:
lf = f.casefold() # 大文字小文字を無視したいのでcasefold
if lf.endswith((".csv", ".tsv")):
print(f"{f}: 表データとして読み込みます。")
elif lf.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp")):
print(f"{f}: 画像ファイルです。")
elif lf.endswith((".tar.gz", ".zip")):
print(f"{f}: 圧縮アーカイブです。")
elif lf.endswith(".pdf"):
print(f"{f}: PDF文書です。")
else:
print(f"{f}: 対象外です。")
report.pdf: PDF文書です。
data.csv: 表データとして読み込みます。
archive.tar.gz: 圧縮アーカイブです。
image.PNG: 画像ファイルです。
README: 対象外です。
script.Py: 対象外です。
注意点として、.tar.gz
のような複合拡張子は.gz
だけで判定すると誤分類しがちです。
必要に応じて複合拡張子を優先してチェックします。
URLやパスをstartswithで判定
URLのスキームやファイルパスのルートを判定する例です。
samples = [
"https://example.com",
"http://example.com",
"ftp://ftp.example.com",
"/usr/local/bin/python",
"C:\\Windows\\System32",
"\\\\server\\share\\folder" # WindowsのUNCパス
]
for s in samples:
if s.startswith(("http://", "https://")):
print(f"{s}: Web URLです。")
elif s.startswith("ftp://"):
print(f"{s}: FTP URLです。")
elif s.startswith(("/", "\\\\", "C:\\", "D:\\")): # 先頭で粗く判定
print(f"{s}: ローカル/ネットワークパスです。")
else:
print(f"{s}: 種別不明です。")
https://example.com: Web URLです。
http://example.com: Web URLです。
ftp://ftp.example.com: FTP URLです。
/usr/local/bin/python: ローカル/ネットワークパスです。
C:\Windows\System32: ローカル/ネットワークパスです。
\\server\share\folder: ローカル/ネットワークパスです。
実務ではOSごとにパス表現が異なるため、標準ライブラリpathlib
での厳密な判定や操作を併用すると堅牢になります。
本記事では先頭文字の判定に焦点を当てています。
前後の空白を無視して判定 stripを併用
入力値の前後に空白や改行が含まれることはよくあります。
strip()
で前後の空白を取り除いたうえで判定します。
raw_inputs = [" hello.py ", "\tINDEX.HTML\n", " notes.md\n"]
for raw in raw_inputs:
s = raw.strip() # 前後の空白・改行を削除
if s.casefold().endswith((".py", ".html", ".md")):
print(f"{repr(raw)} → OK: {s}")
else:
print(f"{repr(raw)} → NG: {s}")
' hello.py ' → OK: hello.py
'\tINDEX.HTML\n' → OK: INDEX.HTML
' notes.md\n' → OK: notes.md
改行だけを確実に取りたい場合はrstrip("\n")
を使う選択肢もあります。
strip(".")
のように引数を渡すと「集合として扱われる文字の除去」になる点には注意します(後述)。
注意点とベストプラクティス
inや==との違いと使い分け
似た判定との違いを整理します。
startswith
/endswith
: 先頭(または末尾)に限定して一致を確認。境界に意味があるときに使います。in
: 文字列のどこかに部分一致していればTrue。位置は問わないため、境界条件が重要な場合には不適切です。==
: 完全一致。先頭・末尾だけを見たい場合には過剰です。
以下は簡単な比較例です。
s = "abracadabra"
print(s.startswith("abra")) # 先頭限定
print("abra" in s) # どこかに含まれる
print(s.endswith("dabra")) # 末尾限定
print(s == "abra") # 完全一致
True
True
True
False
上の例では"abra"
は先頭にも含まれていますが、==
はFalseになります。
用途に応じて最小限で明確なメソッドを選ぶと読みやすく安全です。
正規表現との使い分け
複雑なパターンや繰り返し、数値範囲などを含む場合はre
モジュールが有効です。
しかし「固定文字列で始まる/終わる」だけならstartswith
/endswith
がシンプルで高速です。
正規表現を使うべきケース:
- 可変桁の数字や選択、グルーピングが必要なとき
- アンカー
^
(行頭)や$
(行末)に加え、複数の条件を同時に表現したいとき
startswith
/endswith
で十分なケース:
- 固定の接頭辞・接尾辞の一致
- 拡張子やスキームなど限定的な判定
目安として、「パターンが固定文字列のみ」ならstartswith
/endswith
をまず検討します。
よくある落とし穴と対策
初心者がつまずきやすいポイントと対策を整理します。
- タプル以外(リストなど)を渡してTypeError
- NG:
name.endswith([".jpg", ".png"])
- OK:
name.endswith((".jpg", ".png"))
- リストを持っている場合は
tuple(list_obj)
でタプルに変換します。
- NG:
or
の誤用で1個しか判定されない- NG:
name.endswith(".jpg" or ".png")
→ 実際は".jpg"
だけを判定 - OK:
name.endswith((".jpg", ".png"))
- NG:
- 型の不一致
str
に対してbytes
の接頭辞(またはその逆)は渡せません。TypeError
となります。同じ型同士で比較してください。
- 大文字小文字の誤判定
- 既定は区別されます。大小無視にしたいなら
casefold()
(またはlower()
)で揃えてから判定します。
- 既定は区別されます。大小無視にしたいなら
- 改行の混入による失敗
- ファイルから読み込んだ行は末尾に
\n
があることが多いです。必要に応じてrstrip("\n")
やstrip()
を使います。
- ファイルから読み込んだ行は末尾に
start
/end
の解釈ミスend
は「含まない」位置です。スライスのルールと同じです。負のインデックスも使えます。
- 複合拡張子の取り扱い
.tar.gz
のようなケースは.gz
だけで判定すると意図と異なる結果になります。複合拡張子を先に、またはタプルに含めて明示的に扱います。
strip
の引数の誤解strip(".py")
は「文字.
とp
とy
の集合を除去」します。拡張子を安全に取り除く用途には不向きです。単に判定したいならendswith(".py")
を使います。
参考までに用途別の目安を簡単にまとめます。
目的 | 推奨 |
---|---|
固定の接頭辞・接尾辞の判定 | startswith / endswith |
文字列のどこかに含まれるか | in |
完全一致かどうか | == |
複雑なパターンや数値条件を含む | re(正規表現) |
まとめ
startswith
とendswith
は、文字列の境界に注目した判定を安全かつ簡潔に書ける基本メソッドです。
基本構文を押さえたうえで、複数候補のタプル指定、start
/end
による部分範囲、casefold
による大小無視などを活用すれば、多くの実務シーンに対応できます。
また、in
や==
、正規表現との使い分けを理解することで、過不足なく意図が伝わるコードになります。
最後に、タプルの指定やstrip
の挙動、複合拡張子などの落とし穴に注意し、読みやすく堅牢な文字列判定を書いていきましょう。