閉じる

【Python】文字列が特定の文字で始まる/終わるかを判定する

文字列が特定の文字で始まるか、または終わるかを判定する処理は、データのフィルタリングやバリデーションで頻出します。

Pythonにはこの目的に特化したstartswithendswithがあり、直感的で安全に判定できます。

本記事では基本から応用、実用例、注意点まで段階的に解説します。

Pythonのstartswithとendswithの基本

startswithの基本構文と使い方

str.startswith(prefix[, start[, end]])は、文字列が指定したprefixで始まっているかを真偽値で返します。

startendは検索範囲(スライス)を指定する任意引数です。

Python
# 基本的なstartswithの使い方
s = "Hello, world!"

print(s.startswith("He"))     # "He"で始まるか
print(s.startswith("he"))     # 大文字小文字は区別される
print(s.startswith("Hello,")) # 複数文字の接頭辞もOK
実行結果
True
False
True

先頭ではなく、途中からの判定

startendを指定すると、文字列の一部範囲に対して「その範囲の先頭がprefixか」を判定できます。

endはスライス同様に末尾は含まれません。

Python
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で終わっているかを真偽値で返します。

startendの解釈はstartswithと同様です。

Python
# 基本的なendswithの使い方
s = "report_final.pdf"

print(s.endswith(".pdf"))  # ".pdf"で終わるか
print(s.endswith("PDF"))   # 大文字小文字は区別される
実行結果
True
False

一部範囲での末尾判定

部分範囲の「末尾がsuffixか」を判定できます。

Python
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文での使い方と真偽値

startswithendswithは真偽値(True/False)を返すため、そのままif条件に使えます。

Python
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の応用テクニック

複数候補を一度に判定する

prefixsuffixにタプルを渡すと、いずれかに一致すればTrueになります。

拡張子やプロトコルの判定に便利です。

Python
# 画像拡張子のいずれかで終わるかを判定
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引数で部分範囲を指定

ログの行頭タイムスタンプやファイル名の特定位置のパターンなど、文字列全体ではなく一部範囲を対象にできます。

Python
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()が推奨です。

Python
# 大文字小文字を無視した先頭・末尾判定
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で判定

拡張子によって処理を分けるのは定番です。

複数の拡張子をまとめて扱う例を示します。

Python
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のスキームやファイルパスのルートを判定する例です。

Python
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()で前後の空白を取り除いたうえで判定します。

Python
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。位置は問わないため、境界条件が重要な場合には不適切です。
  • ==: 完全一致。先頭・末尾だけを見たい場合には過剰です。

以下は簡単な比較例です。

Python
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)でタプルに変換します。
  • orの誤用で1個しか判定されない
    • NG: name.endswith(".jpg" or ".png") → 実際は".jpg"だけを判定
    • OK: name.endswith((".jpg", ".png"))
  • 型の不一致
    • strに対してbytesの接頭辞(またはその逆)は渡せません。TypeErrorとなります。同じ型同士で比較してください。
  • 大文字小文字の誤判定
    • 既定は区別されます。大小無視にしたいならcasefold()(またはlower())で揃えてから判定します。
  • 改行の混入による失敗
    • ファイルから読み込んだ行は末尾に\nがあることが多いです。必要に応じてrstrip("\n")strip()を使います。
  • start/endの解釈ミス
    • endは「含まない」位置です。スライスのルールと同じです。負のインデックスも使えます。
  • 複合拡張子の取り扱い
    • .tar.gzのようなケースは.gzだけで判定すると意図と異なる結果になります。複合拡張子を先に、またはタプルに含めて明示的に扱います。
  • stripの引数の誤解
    • strip(".py")は「文字.pyの集合を除去」します。拡張子を安全に取り除く用途には不向きです。単に判定したいならendswith(".py")を使います。

参考までに用途別の目安を簡単にまとめます。

目的推奨
固定の接頭辞・接尾辞の判定startswith / endswith
文字列のどこかに含まれるかin
完全一致かどうか==
複雑なパターンや数値条件を含むre(正規表現)

まとめ

startswithendswithは、文字列の境界に注目した判定を安全かつ簡潔に書ける基本メソッドです。

基本構文を押さえたうえで、複数候補のタプル指定、start/endによる部分範囲、casefoldによる大小無視などを活用すれば、多くの実務シーンに対応できます。

また、in==、正規表現との使い分けを理解することで、過不足なく意図が伝わるコードになります。

最後に、タプルの指定やstripの挙動、複合拡張子などの落とし穴に注意し、読みやすく堅牢な文字列判定を書いていきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!