目的別のPython文字列操作テクニックまとめ
1. 文字列の生成と連結 ✨
文字列リテラルの作成方法や、複数の文字列を結合する方法です。
1.1. 基本的な生成
シングルクォート'
またはダブルクォート"
で囲みます。
s1 = 'これは文字列です。'
s2 = "This is also a string."
print(s1)
print(s2)
1.2. 複数行文字列
トリプルクォート'''
または"""
で囲むと、改行を含む文字列を作成できます。
multi_line_str = """複数行にわたる
文字列を
定義できます。"""
print(multi_line_str)
1.3. + 演算子による連結
文字列同士を +
で連結します。
str1 = "こんにちは"
str2 = "世界"
result = str1 + "、" + str2 + "!" # 変数やリテラルを連結
print(result) # 出力: こんにちは、世界!
注意点: 大量の文字列を連結する場合、+
演算子は中間文字列を生成するため非効率になることがあります。その場合は str.join()
を検討してください。
1.4. * 演算子による繰り返し
文字列を整数倍して繰り返します。
separator = "-" * 10 # "-" を 10 回繰り返す
print(separator) # 出力: ----------
laugh = "ha" * 3
print(laugh) # 出力: hahaha
1.5. str() による型変換
他のデータ型(数値など)を文字列に変換します。
age = 30
message = "私の年齢は" + str(age) + "歳です。" # int を str に変換して連結
print(message)
pi = 3.14159
pi_str = "円周率は " + str(pi) + " です。"
print(pi_str)
1.6. f-string (フォーマット済み文字列リテラル) 🚀
Python 3.6以降で推奨される、最も簡潔で読みやすいフォーマット方法です。文字列リテラルの前に f
または F
を付け、{}
内に変数や式を記述します。
name = "太郎"
age = 25
height = 175.5
# 基本的な使い方
info = f"名前: {name}, 年齢: {age}歳"
print(info) # 出力: 名前: 太郎, 年齢: 25歳
# 式も埋め込める
calculation = f"年齢の10年後は {age + 10} 歳です。"
print(calculation) # 出力: 年齢の10年後は 35 歳です。
# 書式指定も可能(例: 小数点以下2桁)
height_info = f"身長: {height:.2f} cm"
print(height_info) # 出力: 身長: 175.50 cm
# 波括弧 자체를 출력하고 싶은 경우
braces_info = f"波括弧を表示: {{}} , 変数: {name}"
print(braces_info) # 出力: 波括弧を表示: {} , 変数: 太郎
書式指定の詳細は Python公式ドキュメントの書式指定ミニ言語仕様 を参照してください。
1.7. str.format() メソッド
f-stringが登場する前から使われているフォーマット方法です。{}
プレースホルダーを文字列内に配置し、format()
メソッドの引数で値を渡します。
item = "リンゴ"
price = 150
quantity = 3
# 位置引数
order1 = "商品: {}, 価格: {}円, 個数: {}".format(item, price, quantity)
print(order1) # 出力: 商品: リンゴ, 価格: 150円, 個数: 3
# インデックス指定
order2 = "商品: {0}, 個数: {2}, 価格: {1}円".format(item, price, quantity)
print(order2) # 出力: 商品: リンゴ, 個数: 3, 価格: 150円
# キーワード引数
order3 = "商品: {product}, 価格: {cost}円".format(product=item, cost=price)
print(order3) # 出力: 商品: リンゴ, 価格: 150円
# 書式指定(例: ゼロ埋め5桁)
order_id = 123
formatted_id = "注文番号: {:05d}".format(order_id)
print(formatted_id) # 出力: 注文番号: 00123
1.8. % 演算子 (旧スタイル)
C言語の printf
スタイルに似た古い形式です。現在は f-string や str.format()
の利用が推奨されますが、既存のコードやログ出力などで見られます。
name = "花子"
score = 85.5
# 文字列 (%s), 整数 (%d), 浮動小数点数 (%f)
result = "名前: %s, スコア: %.1f点" % (name, score) # %.1f は小数点以下1桁
print(result) # 出力: 名前: 花子, スコア: 85.5点
# 辞書を使ったマッピング
data = {"person": "次郎", "age": 28}
info = "名前: %(person)s, 年齢: %(age)d" % data
print(info) # 出力: 名前: 次郎, 年齢: 28
1.9. str.join() メソッド 🔗
文字列のリスト(や他のイテラブル)を、指定した区切り文字で連結します。+
演算子よりも効率的な場合が多いです。
words = ["Python", "is", "fun"]
sentence = " ".join(words) # スペースで連結
print(sentence) # 出力: Python is fun
chars = ["a", "b", "c"]
combined = "".join(chars) # 区切り文字なしで連結
print(combined) # 出力: abc
data = ["2025", "04", "01"]
date_str = "-".join(data) # ハイフンで連結
print(date_str) # 出力: 2025-04-01
# 数値などが含まれる場合は、事前に文字列に変換する必要がある
items = ["apple", 100, "orange", 200]
# NG例: print(",".join(items)) -> TypeError
# OK例:
items_str = [str(item) for item in items]
print(", ".join(items_str)) # 出力: apple, 100, orange, 200
2. 文字列の分割と置換 ✂️
文字列を特定のルールで分割したり、一部を別の文字列に置き換えたりします。
2.1. str.split(sep=None, maxsplit=-1)
指定した区切り文字 sep
で文字列を分割し、リストを返します。
sep
を省略またはNone
にすると、空白文字(スペース、タブ、改行など)で分割します。連続する空白は1つの区切り文字として扱われます。maxsplit
で分割回数の最大値を指定できます。指定した回数分割すると、残りは最後の要素に含まれます。-1
は制限なし(デフォルト)。
text1 = "apple,orange,banana"
fruits = text1.split(',') # カンマで分割
print(fruits) # 出力: ['apple', 'orange', 'banana']
text2 = "one two three\nfour"
words = text2.split() # 空白文字で分割
print(words) # 出力: ['one', 'two', 'three', 'four']
text3 = "a-b-c-d-e"
parts1 = text3.split('-', maxsplit=2) # 最大2回分割
print(parts1) # 出力: ['a', 'b', 'c-d-e']
# 区切り文字が見つからない場合、元の文字列を含むリストを返す
text4 = "hello"
result = text4.split(',')
print(result) # 出力: ['hello']
2.2. str.rsplit(sep=None, maxsplit=-1)
split()
と同様ですが、文字列の右側(末尾)から分割を開始します。maxsplit
の挙動が異なります。
text = "a-b-c-d-e"
parts_r = text.rsplit('-', maxsplit=2) # 右から最大2回分割
print(parts_r) # 出力: ['a-b-c', 'd', 'e']
2.3. str.splitlines(keepends=False)
文字列を改行コード(\n
, \r
, \r\n
など)で分割し、各行のリストを返します。
keepends=True
にすると、返されるリストの各要素の末尾に改行コードが含まれます。
text_lines = "First line\nSecond line\r\nThird line"
lines = text_lines.splitlines()
print(lines) # 出力: ['First line', 'Second line', 'Third line']
lines_with_ends = text_lines.splitlines(keepends=True)
print(lines_with_ends) # 出力: ['First line\n', 'Second line\r\n', 'Third line']
2.4. str.partition(sep)
文字列内で最初に見つかった区切り文字 sep
で文字列を3つの部分(sep
の前の部分, sep
自身, sep
の後の部分)に分割し、タプルで返します。
sep
が見つからない場合は、(元の文字列, ”, ”) というタプルを返します。
text = "user@example.com"
parts = text.partition('@')
print(parts) # 出力: ('user', '@', 'example.com')
text_no_sep = "filename.txt"
parts_no_sep = text_no_sep.partition(':')
print(parts_no_sep) # 出力: ('filename.txt', '', '')
2.5. str.rpartition(sep)
partition()
と同様ですが、文字列内で最後に現れた区切り文字 sep
で分割します。
path = "/usr/local/bin/python"
dir_sep_file = path.rpartition('/')
print(dir_sep_file) # 出力: ('/usr/local/bin', '/', 'python')
2.6. str.replace(old, new, count=-1) 🔄
文字列中の部分文字列 old
を new
に置換します。
count
で置換する最大回数を指定できます。-1
は全て置換(デフォルト)。- 元の文字列は変更されず、新しい文字列が返されます。
message = "Hello world, hello Python!"
new_message1 = message.replace("hello", "Hi") # 大文字小文字を区別する
print(new_message1) # 出力: Hello world, Hi Python!
new_message2 = message.replace(" ", "_") # スペースをアンダースコアに置換
print(new_message2) # 出力: Hello_world,_hello_Python!
new_message3 = message.replace("l", "L", 3) # 最初から3つの 'l' を 'L' に置換
print(new_message3) # 出力: HeLLo worLd, hello Python!
2.7. str.translate(table) / str.maketrans(x, y, z)
複数の文字を一度に対応する文字に置換したり、特定の文字を削除したりします。maketrans()
で変換テーブルを作成し、translate()
に渡すのが一般的です。
maketrans(x, y)
: 文字列x
の各文字を、文字列y
の同じ位置にある文字にマッピングするテーブルを作成(x
とy
は同じ長さである必要があります)。maketrans(x, y, z)
: 上記に加え、文字列z
に含まれる全ての文字を削除(None
にマッピング)するテーブルを作成。maketrans(dict)
: {文字コード(int): 置換先(str/int/None)} の辞書からテーブルを作成。
# 特定の文字を置換
text1 = "abcde"
trans_table1 = str.maketrans("ae", "AE") # 'a' -> 'A', 'e' -> 'E'
translated1 = text1.translate(trans_table1)
print(translated1) # 出力: AbcdE
# 特定の文字を削除
text2 = "Hello, world!"
trans_table2 = str.maketrans("", "", ",!") # カンマと感嘆符を削除
translated2 = text2.translate(trans_table2)
print(translated2) # 出力: Hello world
# 置換と削除を同時に行う
text3 = "Remove Vowels Example"
trans_table3 = str.maketrans("aeiou", "AEIOU", " ") # 母音を大文字にし、スペースを削除
translated3 = text3.translate(trans_table3)
print(translated3) # 出力: RmvVwlsExmpl
# 辞書を使ったテーブル作成 (全角英数を半角に変換する例)
zen = "ABC123"
han = "ABC123"
# 全角 -> 半角 の変換テーブル(一部)
# ord() で文字コードを取得
trans_table_dict = str.maketrans(
{ord(z): h for z, h in zip(zen, han)}
)
translated_dict = zen.translate(trans_table_dict)
print(translated_dict) # 出力: ABC123
3. 文字列の検索と判定 🔍
文字列内に特定のパターンが存在するかどうかを調べたり、文字列の特性(数字のみか、アルファベットのみかなど)を判定したりします。
3.1. in 演算子
部分文字列が文字列内に含まれているかを判定し、True
/ False
を返します。
text = "Python programming is fun."
print("Python" in text) # 出力: True
print("Java" in text) # 出力: False
print("gram" in text) # 出力: True
print("Fun" in text) # 出力: False (大文字小文字を区別)
3.2. 検索メソッド: find, rfind, index, rindex
部分文字列が最初または最後に現れるインデックス(位置)を返します。
メソッド | 説明 | 見つからない場合の戻り値 | 例 |
---|---|---|---|
find(sub[, start[, end]]) |
文字列の左から部分文字列 sub を検索し、最初に見つかったインデックスを返す。 |
-1 |
"abcabc".find("bc") → 1 |
rfind(sub[, start[, end]]) |
文字列の右から部分文字列 sub を検索し、最初に見つかったインデックスを返す。 |
-1 |
"abcabc".rfind("bc") → 4 |
index(sub[, start[, end]]) |
find() と同様だが、見つからない場合にエラー (ValueError ) を送出する。 |
ValueError |
"abcabc".index("bc") → 1 |
rindex(sub[, start[, end]]) |
rfind() と同様だが、見つからない場合にエラー (ValueError ) を送出する。 |
ValueError |
"abcabc".rindex("bc") → 4 |
text = "This is a test string. This is fun."
print(f"find('is'): {text.find('is')}") # 出力: find('is'): 2
print(f"rfind('is'): {text.rfind('is')}") # 出力: rfind('is'): 26
print(f"find('is', 5): {text.find('is', 5)}") # 5文字目以降で検索 -> 出力: find('is', 5): 5
print(f"find('xyz'): {text.find('xyz')}") # 出力: find('xyz'): -1
try:
print(f"index('is'): {text.index('is')}") # 出力: index('is'): 2
print(f"index('xyz'): {text.index('xyz')}") # ここで ValueError が発生
except ValueError as e:
print(f"index('xyz') failed: {e}") # 出力: index('xyz') failed: substring not found
start
と end
引数で検索範囲を指定できます(スライスと同様の指定方法)。
3.3. str.count(sub[, start[, end]])
文字列中に部分文字列 sub
が出現する回数を返します。
text = "banana bandana"
print(f"count('an'): {text.count('an')}") # 出力: count('an'): 4
print(f"count('ana'): {text.count('ana')}") # 出力: count('ana'): 3
print(f"count('a'): {text.count('a')}") # 出力: count('a'): 6
print(f"count('an', 0, 6): {text.count('an', 0, 6)}") # 最初の6文字 "banana" 内で 'an' をカウント -> 出力: count('an', 0, 6): 2
3.4. str.startswith(prefix[, start[, end]])
文字列が指定した接頭辞 prefix
で始まるかどうかを判定します。prefix
は文字列のタプルでも指定でき、その場合はいずれか一つにマッチすれば True
となります。
filename = "document.txt"
print(filename.startswith("doc")) # 出力: True
print(filename.startswith("Doc")) # 出力: False (大文字小文字を区別)
print(filename.startswith(("image", "doc"))) # "image" または "doc" で始まるか -> 出力: True
url = "https://example.com"
print(url.startswith("http")) # 出力: True
# 範囲を指定して判定 (8文字目以降が "example" で始まるか)
print(url.startswith("example", 8)) # 出力: True
3.5. str.endswith(suffix[, start[, end]])
文字列が指定した接尾辞 suffix
で終わるかどうかを判定します。suffix
もタプルで指定可能です。
filename = "report.pdf"
print(filename.endswith(".pdf")) # 出力: True
print(filename.endswith(".txt")) # 出力: False
print(filename.endswith((".pdf", ".docx"))) # ".pdf" または ".docx" で終わるか -> 出力: True
text = "Hello World"
# 範囲を指定して判定 (最初の5文字 "Hello" が "lo" で終わるか)
print(text.endswith("lo", 0, 5)) # 出力: True
3.6. 文字種別判定メソッド 🤔
文字列が特定の種類の文字(英数字、数字、空白など)だけで構成されているかを判定するメソッド群です。全て True
/ False
を返します。空文字列に対しては全て False
を返します。
メソッド | 説明 | 例 (True) | 例 (False) |
---|---|---|---|
isalnum() |
全ての文字が英数字(アルファベット or 数字)であり、かつ1文字以上あるか。 | "abc123" , "Python3" |
"abc 123" , "Python-3" , "" |
isalpha() |
全ての文字がアルファベットであり、かつ1文字以上あるか。 | "abc" , "Python" , "あいう" |
"abc1" , "Python 3" , "" |
isascii() |
全ての文字がASCII文字(U+0000-U+007F)であるか、または空文字列か。 | "Hello" , "123!@#" , "" |
"こんにちは" , "你好" |
isdigit() |
全ての文字が数字(0-9)であり、かつ1文字以上あるか。 | "12345" |
"123.45" , "-123" , "123a" , "①②③" , "" |
isdecimal() |
全ての文字が十進数文字であり、かつ1文字以上あるか。(UnicodeのDecimalカテゴリ) | "12345" , "٠١٢٣" (アラビア数字) |
"123.45" , "①②③" (数字だが十進数ではない), "¹²³" (上付き文字), "" |
isnumeric() |
全ての文字が数値文字(数字、分数、ローマ数字、漢数字などを含む)であり、かつ1文字以上あるか。(UnicodeのNumericカテゴリ) | "123" , "¹²³" , "½" , "一二三" , "①②③" |
"123.45" , "-123" , "abc" , "" |
islower() |
全てのアルファベット文字が小文字であり、かつアルファベットが1文字以上含まれるか。 | "hello world" , "python 3" |
"Hello world" , "PYTHON" , "123" , "" |
isupper() |
全てのアルファベット文字が大文字であり、かつアルファベットが1文字以上含まれるか。 | "HELLO WORLD" , "PYTHON 3" |
"Hello world" , "python" , "123" , "" |
isspace() |
全ての文字が空白文字(スペース、タブ \t , 改行 \n , 復帰 \r など)であり、かつ1文字以上あるか。 |
" " , "\t\n " |
" a " , "Hello" , "" |
istitle() |
文字列がタイトルケース(単語の先頭が大文字で、残りが小文字)であり、かつアルファベットが1文字以上含まれるか。数字や記号の後の文字は小文字でもよい。 | "Title Case String" , "Python Is Fun" , "1st Word" |
"Title case string" , "python is fun" , "TITLE" , "" |
isidentifier() |
文字列がPythonの有効な識別子(変数名、関数名など)として使えるか。キーワードは False になる。 |
"variable_name" , "myFunc" , "_private" , "変数1" |
"1variable" , "my-func" , "class" (キーワード), "" |
isprintable() |
文字列中の全ての文字が印字可能文字(改行 \n やタブ \t などの制御文字以外)であるか、または空文字列か。空白は印字可能とみなされる。 |
"Hello World 123!?" , " " , "" |
"Hello\nWorld" , "abc\tdef" |
print(f"'abc123'.isalnum(): {'abc123'.isalnum()}") # True
print(f"'123'.isdigit(): {'123'.isdigit()}") # True
print(f"'¹²³'.isnumeric(): {'¹²³'.isnumeric()}") # True (isdigit() は False)
print(f"' '.isspace(): {' '.isspace()}") # True
print(f"'Hello World'.istitle(): {'Hello World'.istitle()}") # True
print(f"'my_var'.isidentifier(): {'my_var'.isidentifier()}") # True
print(f"'class'.isidentifier(): {'class'.isidentifier()}") # False (キーワード)
print(f"'你好'.isprintable(): {'你好'.isprintable()}") # True
print(f"'Hello\\n'.isprintable(): {'Hello\\n'.isprintable()}") # False
4. 文字列の整形と変換 🎨
文字列の見た目を整えたり、大文字/小文字を変換したり、特定の文字を除去したりします。
4.1. 空白除去メソッド: strip, lstrip, rstrip
文字列の両端、左端、右端から指定した文字(デフォルトは空白文字)を除去します。
メソッド | 説明 | 例 | 出力 |
---|---|---|---|
strip([chars]) |
両端から chars に含まれる文字を除去。chars 省略時は空白文字。 |
" spacious ".strip() ".,xyABCxy.,".strip('.,xy') |
"spacious" "ABC" |
lstrip([chars]) |
左端(先頭)から chars に含まれる文字を除去。chars 省略時は空白文字。 |
" spacious ".lstrip() ".,xyABCxy.,".lstrip('.,xy') |
"spacious " "ABCxy.," |
rstrip([chars]) |
右端(末尾)から chars に含まれる文字を除去。chars 省略時は空白文字。 |
" spacious ".rstrip() ".,xyABCxy.,".rstrip('.,xy') |
" spacious" ".,xyABC" |
text = "\t \n Hello World \n\r "
print(f"Original: '{text}'")
print(f"strip(): '{text.strip()}'") # 両端の空白を除去
print(f"lstrip(): '{text.lstrip()}'") # 左端の空白を除去
print(f"rstrip(): '{text.rstrip()}'") # 右端の空白を除去
csv_data = "***,,value1,,***"
# '*' と ',' を両端から除去
print(f"strip('*,'): '{csv_data.strip('* ,')}'") # -> value1
4.2. 大文字/小文字変換メソッド
文字列内のアルファベットの大文字と小文字を変換します。
メソッド | 説明 | 例 | 出力 |
---|---|---|---|
lower() |
全てのアルファベットを小文字に変換。 | "PyThoN".lower() |
"python" |
upper() |
全てのアルファベットを大文字に変換。 | "PyThoN".upper() |
"PYTHON" |
capitalize() |
文字列の先頭の文字を大文字に、残りを小文字に変換。 | "pyThoN is FUN".capitalize() |
"Python is fun" |
title() |
各単語の先頭文字を大文字に、残りを小文字に変換(タイトルケース)。単語の区切りは空白や記号など。 | "pyThoN is FUN".title() "they're".title() |
"Python Is Fun" "They'Re" (注意: アポストロフィの後も大文字になる) |
swapcase() |
大文字と小文字を入れ替える。 | "PyThoN is Fun".swapcase() |
"pYtHOn IS fUN" |
text = "lOwEr, UPPER, Title, cAPITALIZE"
print(f"lower(): {text.lower()}")
print(f"upper(): {text.upper()}")
print(f"capitalize(): {text.capitalize()}")
print(f"title(): {text.title()}")
print(f"swapcase(): {text.swapcase()}")
4.3. 寄せ/埋め込みメソッド: center, ljust, rjust, zfill
指定した幅の中で文字列を配置したり、指定した文字で埋めたりします。
メソッド | 説明 | 例 | 出力 |
---|---|---|---|
center(width[, fillchar]) |
指定した width の中央に文字列を配置。余白は fillchar (デフォルトはスペース) で埋める。 |
"abc".center(10) "abc".center(10, '-') |
" abc " "---abc----" |
ljust(width[, fillchar]) |
指定した width の左側に文字列を配置。右側の余白は fillchar で埋める。 |
"abc".ljust(10) "abc".ljust(10, '*') |
"abc " "abc*******" |
rjust(width[, fillchar]) |
指定した width の右側に文字列を配置。左側の余白は fillchar で埋める。 |
"abc".rjust(10) "abc".rjust(10, '0') |
" abc" "0000000abc" |
zfill(width) |
指定した width になるように、文字列の左側をゼロ ‘0’ で埋める。符号 (+ , - ) は先頭に維持される。 |
"42".zfill(5) "-42".zfill(5) |
"00042" "-0042" |
text = "Data"
width = 12
print(f"center: '{text.center(width, '=')}'")
print(f"ljust: '{text.ljust(width)}'")
print(f"rjust: '{text.rjust(width, '_')}'")
print(f"zfill: '{'123'.zfill(width)}'")
print(f"zfill: '{'-123'.zfill(width)}'")
4.4. str.expandtabs(tabsize=8)
文字列中のタブ文字 \t
を、指定された tabsize
(デフォルトは8) のスペースに置き換えます。タブ位置は累積的に計算されます。
text = "col1\tcol2\tcol3"
expanded_default = text.expandtabs()
expanded_custom = text.expandtabs(tabsize=4)
print(f"Original: '{text}'")
print(f"Expanded (8): '{expanded_default}'") # col1 の後 4 スペース, col2 の後 4 スペース
print(f"Expanded (4): '{expanded_custom}'") # col1 の後 1 スペース, col2 の後 1 スペース
text2 = "a\tbc\tdef\tghij"
print(f"'{text2.expandtabs(4)}'") # a の後 3, bc の後 2, def の後 1 スペース
4.5. str.removeprefix(prefix) (Python 3.9+)
文字列が指定した接頭辞 prefix
で始まる場合、その接頭辞を削除した新しい文字列を返します。始まらない場合は元の文字列をそのまま返します。
url = "https://example.com"
print(url.removeprefix("https://")) # 出力: example.com
print(url.removeprefix("http://")) # 出力: https://example.com (変化なし)
filename = "test_data.csv"
print(filename.removeprefix("test_")) # 出力: data.csv
4.6. str.removesuffix(suffix) (Python 3.9+)
文字列が指定した接尾辞 suffix
で終わる場合、その接尾辞を削除した新しい文字列を返します。終わらない場合は元の文字列をそのまま返します。
filename = "image.jpg"
print(filename.removesuffix(".jpg")) # 出力: image
print(filename.removesuffix(".png")) # 出力: image.jpg (変化なし)
code = "function();"
print(code.removesuffix("();")) # 出力: function
5. エンコーディングとデコーディング ↔️
コンピュータが内部で扱うバイト列(bytes
)と、人間が読む文字列(str
)を相互に変換します。ファイル入出力やネットワーク通信で重要です。
5.1. str.encode(encoding='utf-8', errors='strict')
文字列 (str
) を指定した encoding
を使ってバイト列 (bytes
) に変換(エンコード)します。
- 一般的なエンコーディング:
'utf-8'
(推奨),'shift_jis'
(Windows日本語),'euc-jp'
(Unix日本語),'cp932'
(Shift_JISの亜種) errors
: エンコードできない文字があった場合の処理方法を指定します。'strict'
:UnicodeEncodeError
を送出 (デフォルト)。'ignore'
: エンコードできない文字を無視する。'replace'
: エンコードできない文字を?
に置き換える。'xmlcharrefreplace'
: XML文字参照 (例:Ӓ
) に置き換える。'backslashreplace'
: Pythonのバックスラッシュエスケープシーケンス (例:\u1234
) に置き換える。
text_jp = "こんにちは世界"
text_en = "Hello World"
# UTF-8 (デフォルト)
bytes_utf8 = text_jp.encode() # encoding 省略時は 'utf-8'
print(f"UTF-8: {bytes_utf8}")
# Shift_JIS
try:
bytes_sjis = text_jp.encode('shift_jis')
print(f"Shift_JIS: {bytes_sjis}")
except UnicodeEncodeError as e:
print(f"Shift_JISエンコードエラー: {e}") # Shift_JISにない文字が含まれるとエラー
# エラーハンドリング
text_mixed = "① Python" # ① は Shift_JIS にない
bytes_sjis_ignore = text_mixed.encode('shift_jis', errors='ignore')
print(f"Shift_JIS (ignore): {bytes_sjis_ignore}") # -> b' Python'
bytes_sjis_replace = text_mixed.encode('shift_jis', errors='replace')
print(f"Shift_JIS (replace): {bytes_sjis_replace}") # -> b'? Python'
5.2. bytes.decode(encoding='utf-8', errors='strict')
バイト列 (bytes
) を指定した encoding
を使って文字列 (str
) に変換(デコード)します。
encoding
とerrors
はencode()
と同様ですが、デコードできないバイトシーケンスに対する処理になります。errors='strict'
の場合、不正なバイトシーケンスがあるとUnicodeDecodeError
を送出します。
bytes_utf8 = b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf\xe4\xb8\x96\xe7\x95\x8c'
bytes_sjis = b'\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x90\xa2\x8a\x E9' # こんにちは世界 (Shift_JIS)
# UTF-8 (デフォルト)
str_from_utf8 = bytes_utf8.decode() # encoding 省略時は 'utf-8'
print(f"Decoded from UTF-8: {str_from_utf8}")
# Shift_JIS
str_from_sjis = bytes_sjis.decode('shift_jis')
print(f"Decoded from Shift_JIS: {str_from_sjis}")
# 間違ったエンコーディングでデコードしようとするとエラーになるか、文字化けする
try:
# Shift_JISのバイト列をUTF-8でデコード
str_error = bytes_sjis.decode('utf-8', errors='strict')
print(str_error)
except UnicodeDecodeError as e:
print(f"デコードエラー: {e}")
# errors='replace' で文字化け部分を置換
str_replace = bytes_sjis.decode('utf-8', errors='replace')
print(f"Decoded with replace: {str_replace}") # -> �������ԁA�E�
重要: エンコード時に使用したエンコーディングと、デコード時に使用するエンコーディングは、原則として一致させる必要があります。異なるエンコーディングを使用すると、文字化けやエラーの原因となります。
6. 正規表現 (re モジュール) 🧩
複雑なパターンマッチングや文字列操作を行うための強力なツールです。import re
して利用します。
ここでは基本的な関数を紹介します。正規表現パターン自体の書き方は多岐にわたるため、別途学習が必要です。(参考: Python公式 re ドキュメント, 正規表現 HOWTO)
6.1. 検索: re.search(pattern, string, flags=0)
文字列 string
全体を検索し、正規表現 pattern
に最初にマッチした箇所を マッチオブジェクト として返します。マッチしない場合は None
を返します。
import re
text = "Email: user1@example.com, user2@sample.net"
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' # 簡単なメールアドレスパターン
match = re.search(pattern, text)
if match:
print(f"最初にマッチしたメールアドレス: {match.group(0)}") # マッチした文字列全体
print(f"マッチした範囲: {match.span()}")
else:
print("マッチしませんでした。")
6.2. 先頭からマッチ: re.match(pattern, string, flags=0)
文字列 string
の先頭が正規表現 pattern
にマッチするかを試みます。先頭からマッチしない場合は None
を返します。
import re
text1 = "Python is fun"
text2 = "Not Python"
pattern = r"Python"
match1 = re.match(pattern, text1) # 先頭が "Python" なのでマッチ
print(f"text1 match: {match1.group(0) if match1 else None}") # -> Python
match2 = re.match(pattern, text2) # 先頭が "Not" なのでマッチしない
print(f"text2 match: {match2.group(0) if match2 else None}") # -> None
6.3. 完全一致: re.fullmatch(pattern, string, flags=0)
文字列 string
全体が正規表現 pattern
に完全にマッチするかを試みます。完全にマッチしない場合は None
を返します。
import re
text1 = "123-4567"
text2 = "Tel: 123-4567"
pattern = r"\d{3}-\d{4}" # 郵便番号や電話番号形式
match1 = re.fullmatch(pattern, text1) # 文字列全体がパターンにマッチ
print(f"text1 fullmatch: {match1.group(0) if match1 else None}") # -> 123-4567
match2 = re.fullmatch(pattern, text2) # "Tel: " が余計なので完全マッチしない
print(f"text2 fullmatch: {match2.group(0) if match2 else None}") # -> None
6.4. 分割: re.split(pattern, string, maxsplit=0, flags=0)
正規表現 pattern
にマッチする箇所を区切り文字として、文字列 string
を分割し、リストを返します。str.split()
の正規表現版です。
import re
text = "apple, orange; banana\tgrape"
# カンマ、セミコロン、空白文字で分割
pattern = r"[,;\s]\s*" # 区切り文字 + 任意個の空白
parts = re.split(pattern, text)
print(parts) # 出力: ['apple', 'orange', 'banana', 'grape']
6.5. 全て検索: re.findall(pattern, string, flags=0)
文字列 string
中で正規表現 pattern
にマッチする全ての部分を文字列のリストとして返します。マッチが見つからない場合は空のリスト []
を返します。
import re
text = "Numbers: 123, 45, 6789"
pattern = r"\d+" # 1桁以上の数字
numbers = re.findall(pattern, text)
print(numbers) # 出力: ['123', '45', '6789']
6.6. 全て検索 (イテレータ): re.finditer(pattern, string, flags=0)
findall()
と似ていますが、マッチ結果をリストではなくマッチオブジェクトのイテレータとして返します。メモリ効率が良い場合に利用します。
import re
text = "Contact us at info@example.com or support@example.org"
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
matches = re.finditer(pattern, text)
for match in matches:
print(f"Found: {match.group(0)} at {match.span()}")
# 出力:
# Found: info@example.com at (14, 30)
# Found: support@example.org at (34, 53)
6.7. 置換: re.sub(pattern, repl, string, count=0, flags=0)
文字列 string
中で正規表現 pattern
にマッチする部分を repl
(置換文字列または関数) で置換します。str.replace()
の正規表現版です。
count
: 最大置換回数。0は全て置換(デフォルト)。repl
には、マッチした部分を参照する特殊シーケンス(例:\1
,\g<name>
)を使用できます。repl
に関数を指定すると、各マッチオブジェクトを引数として関数が呼び出され、その戻り値が置換文字列として使用されます。
import re
text = " Remove extra spaces. "
pattern = r"\s+" # 1つ以上の連続する空白文字
# 連続する空白を1つのスペースに置換
cleaned_text = re.sub(pattern, " ", text.strip()) # 先に strip() で両端の空白を除去
print(f"'{cleaned_text}'") # 出力: 'Remove extra spaces.'
# マッチ部分を使った置換 (日付形式変更)
date_text = "Date: 2025-04-01"
date_pattern = r"(\d{4})-(\d{2})-(\d{2})" # 年(グループ1), 月(グループ2), 日(グループ3)
# グループを参照してフォーマット変更 (\2/\3/\1)
formatted_date = re.sub(date_pattern, r"\2/\3/\1", date_text)
print(formatted_date) # 出力: Date: 04/01/2025
# 関数を使った置換 (数値を2倍にする)
num_text = "Values: 10, 25, 100"
num_pattern = r"\d+"
def double_value(match):
value = int(match.group(0))
return str(value * 2)
doubled_text = re.sub(num_pattern, double_value, num_text)
print(doubled_text) # 出力: Values: 20, 50, 200
6.8. 置換 (置換回数付き): re.subn(pattern, repl, string, count=0, flags=0)
re.sub()
と同じ動作ですが、戻り値が (新しい文字列, 置換回数)
のタプルになります。
import re
text = "apple apple orange apple"
pattern = r"apple"
result_tuple = re.subn(pattern, "banana", text)
print(result_tuple) # 出力: ('banana banana orange banana', 3)
print(f"新しい文字列: {result_tuple[0]}")
print(f"置換回数: {result_tuple[1]}")
6.9. コンパイル: re.compile(pattern, flags=0)
正規表現パターンを事前にコンパイルしておくと、同じパターンを繰り返し使用する場合に効率が向上します。コンパイルされたパターンオブジェクトは、上記で紹介した関数(search
, match
など)をメソッドとして持ちます。
import re
# パターンをコンパイル
email_pattern = re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b')
text1 = "My email is test@example.com"
text2 = "Another one: user.name+tag@sub.domain.co.uk"
match1 = email_pattern.search(text1)
match2 = email_pattern.search(text2)
if match1:
print(f"Email 1: {match1.group(0)}")
if match2:
print(f"Email 2: {match2.group(0)}")
# findall もメソッドとして使える
emails = email_pattern.findall(text1 + ", " + text2)
print(f"All emails: {emails}")
6.10. フラグ (flags)
正規表現の挙動を調整するオプションです。複数のフラグは |
で組み合わせます。
re.IGNORECASE
/re.I
: 大文字小文字を無視してマッチング。re.MULTILINE
/re.M
:^
が各行の先頭、$
が各行の末尾にもマッチするようになる。re.DOTALL
/re.S
:.
が改行文字\n
にもマッチするようになる。re.VERBOSE
/re.X
: パターン内で空白やコメント (#
以降) を無視し、見やすく書けるようにする。re.ASCII
/re.A
:\w
,\W
,\b
,\B
,\d
,\D
,\s
,\S
がASCII文字のみにマッチするようになる。
import re
text = "Python\nPYTHON\npython"
# 大文字小文字無視
pattern_i = r"python"
matches_i = re.findall(pattern_i, text, flags=re.IGNORECASE)
print(f"IGNORECASE: {matches_i}") # -> ['Python', 'PYTHON', 'python']
# 各行の先頭にマッチ
pattern_m = r"^python"
matches_m = re.findall(pattern_m, text, flags=re.MULTILINE | re.IGNORECASE)
print(f"MULTILINE | IGNORECASE: {matches_m}") # -> ['Python', 'PYTHON', 'python']
# VERBOSE フラグで見やすいパターン
pattern_v = r"""
\b # 単語境界
[A-Z0-9._%+-]+ # ユーザー名部分
@ # @ マーク
[A-Z0-9.-]+ # ドメイン名部分
\. # ドット
[A-Z]{2,} # TLD (2文字以上)
\b # 単語境界
"""
email_text = "test@EXAMPLE.com"
match_v = re.search(pattern_v, email_text, flags=re.VERBOSE | re.IGNORECASE)
if match_v:
print(f"VERBOSE | IGNORECASE match: {match_v.group(0)}") # -> test@EXAMPLE.com
コメント