HOWTO · Python

Python で文字列から特殊文字を削除する

このチュートリアルでは、Python で文字列からすべての特殊文字を削除する方法を説明します。

このページの内容

Pythonの文字列から文字を削除するには、まず残したい文字を決めます。str.isalnum() を使う内包表記または filter() は、Unicodeの文字と数字を残します。正規表現なら空白を残すルールを指定でき、str.translate() なら対象の文字を指定できます。各ルールが分かりやすいよう、以下の例では "Hey! What's up bro?" を使います。コード例はそれぞれ独自の入力を定義して変換後の文字列を出力するため、各方法を個別に実行できます。コードと出力のブロックは原文どおりで、内部の表示ラベルも英語のままです。

「特殊文字」の定義

「特殊文字」に一律の定義はありません。句読点だけを指す場合もあれば、句読点と空白、またはASCIIの英字と数字以外すべてを指す場合もあります。文字列を何に使うかに合わせてルールを決めましょう。たとえば、表示名では空白を残し、短い識別子では取り除くことがあります。

Pythonの文字列はUnicodeです。str.isalnum() はUnicodeの文字と数字を認識するため、é や 中 のような文字も残せます。一方、[a-zA-Z0-9] と書いたパターンが対象にするのはASCIIの英字と数字です。そのため、同じ文字ルールを指定しない限り、以下の方法では結果が異なります。

内包表記で英数字以外を削除する

結果を英字と数字だけにしたい場合は、str.isalnum() を使う文字列内包表記を使います。str.join() は残した文字をつなげて新しい文字列を作ります。このルールでは空白と句読点も削除されます。

original = "Hey! What's up bro?"
cleaned = "".join(char for char in original if char.isalnum())
print(cleaned)
HeyWhatsupbro

この判定ではASCII文字だけでなく、Unicodeの文字と数字も残ります。たとえば é のような文字は残り、空白、アポストロフィ、句読点は取り除かれます。

filter()で文字を絞り込む

組み込み関数の filter() は各文字に判定関数を適用し、判定が真となる文字を含むイテレーターを返します。str.isalnum を渡すと、内包表記と同じUnicodeの文字と数字が残り、str.join() でイテレーターを文字列に戻せます。内包表記と同様に、空白は削除されます。

original = "Hey! What's up bro?"
kept = filter(str.isalnum, original)
cleaned = "".join(kept)
print(cleaned)
HeyWhatsupbro

判定関数を再利用したい場合や、すでに定義済みの関数を使う場合は filter() が便利です。この単純な文字列変換では、内包表記を使うと同じルールをより簡潔に表せます。

str.translate()で指定した文字を削除する

削除する文字が決まっていて、それ以外をすべて残したい場合は str.translate() を使います。str.maketrans() は、選択した各文字を削除する変換テーブルを作ります。以下の集合では一般的なASCII句読点を削除します。空白や一覧にない文字はそのまま残ります。

original = "Hey! What's up bro?"
characters_to_remove = "!@#$%^&*()_-+=<>,./?;:'\"[]{}\\|`~"
table = str.maketrans("", "", characters_to_remove)
cleaned = original.translate(table)
print(cleaned)
Hey Whats up bro

入力に合わせて characters_to_remove に文字を追加または削除してください。この方法ですべての句読点が削除されるわけではありません。一覧にない文字は、ASCII以外の句読点も含め、結果に残ります。

正規表現で文字を削除する

re.sub() はパターンに一致する各文字を置き換えます。このパターンはASCIIの英字と数字だけを残すため、句読点だけでなく空白も削除します。図にも同じルールが示されています。英字と数字の範囲はASCIIに限られるため、対象の文字列にその範囲外の文字が含まれる場合は、Unicodeに対応したルールを使ってください。

import re

original = "Hey! What's up bro?"
pattern = r"[^a-zA-Z0-9]"
cleaned = re.sub(pattern, "", original)
print(cleaned)
HeyWhatsupbro

提示された実行証拠では、この例は上に示した出力を生成しています。空白を残すには、r"[^a-zA-Z0-9\s]" のように、許可する文字の集合へ \s を加えます。Pythonの正規表現では文字クラスやフラグを使って別のルールも表せますが、選んだパターンがデータの言語や文字に合っているか確認してください。

map()とラムダ式で文字を変換する

map() は各文字に関数を適用し、イテレーターを返します。ラムダ式では、Unicodeの文字または数字、あるいは空白文字なら元の文字を返し、それ以外は空文字列を返せます。返された文字を結合すると、変換後の文字列ができます。このルールではタブや改行を含む空白が残ります。

original = "Hey! What's up bro?"
cleaned = "".join(
    map(lambda char: char if char.isalnum() or char.isspace() else "", original)
)
print(cleaned)
Hey Whats up bro

単純な包含判定より複雑な処理が必要な場合に使える、文字ごとの変換方法です。英字と数字だけを残すルールであれば、代わりに内包表記または filter() の例を使ってください。

文字のルールに合った方法を選ぶ

  • Unicodeの文字と数字を残して空白を削除する、分かりやすいルールには str.isalnum() を使う内包表記を選びます。
  • 再利用できる判定関数を渡したい場合は filter() を選びます。例では str.isalnum() と同じルールを使います。
  • 既知の文字だけを削除し、空白や一覧にない句読点を含むそれ以外の文字を残す場合は str.translate() を選びます。
  • 削除または保持する文字をパターンで指定する場合は re.sub() を選びます。例のASCII範囲では空白も削除されるため、Unicode文字に対応させたり空白を残したりするにはパターンを調整してください。
  • 文字ごとに変換する処理が必要な場合は、ラムダ式と map() を選びます。例ではUnicodeの文字と数字、空白が残ります。

名前や自然言語の文章を処理する場合は、変換前にアクセント付き文字、非ラテン文字、空白をどう扱うか決めてください。識別子やプロトコル固有の入力では、「特殊文字」という広い考え方に頼らず、仕様に記載された文字集合に正確に合わせましょう。