カネキン伊藤テック

文字列操作

文字列リテラル

ダブルクオート "" で囲むか, シングルクオート '' で囲ったものは文字列になる。三連続の """''' で囲ったものも文字列となる。

s1 = "double quoted string"
s2 = 'single quoted string'

cr = "\r => CR(復帰, キャリッジリターン)"
lf = "\n => LF(改行, 行送り)"
tab = "\t => タブ"
backslash = "\\"

エスケープシーケンスはシングルクオート文字列もダブルクオート文字列も両方同じように解釈される。 その他のエスケープシーケンスは 2.4.1. 文字列およびバイト列リテラル で確認できる。( \a \b \v など)

N文字目の文字を得る(インデックスによるアクセス)

listtuple のようにインデックスでアクセスすることで文字を取り出すことができる。Pythonには文字型と文字列型の区別はないので、インデックスで文字を取り出して得られるのは長さ1の文字列( str 型)ということになる。

s = "hello"
s[0]  #=> "h" 最初のインデックスはゼロ
s[1]  #=> "e"
s[4]  #=> "o"
s[5]  #=> 存在しない位置にアクセスしようとすると例外IndexErrorが送出される

# マイナスの添え字を使うと後ろから参照できる(-1が一番うしろ)
s[-1]  #=> "o"

インデックスで部分文字列を得る(スライス)

list と同じようにスライスで部分文字列を切り出すことができる。 s[N:M] で得られる文字列の長さは M-N 。逆に考えるとインデックス X から Y 文字欲しかったら s[X:X+Y] と書けばよい。

s = "hello world"
s[0:3]  # "hel" 頭から3文字

s[2:5]  # "llo" 3文字目から3文字

s[-5:]  # "world" 後ろから5文字目から最後まで(最後の5文字)

文字列の長さ(文字数)を数える

組み込み関数 len() で取得できる。

s = "hello"
int(s)  #=> 5

1文字ずつ処理する

for で順番に文字を処理できる。

s = "hello"

for char in s:
	print(char)

文字のリストに変換する

list() にかけると文字のリストになる。

s = "hello"
list(s)  #=> ["h", "e", "l", "l", "o"]

文字列を連結

+ 演算子で連結できる。

a = "hello, "
b = "world!"
c = a + b
print(c)  #=> "hello, world!"

# 3つ以上も連結できる
d = "Alpha" + "Bravo" + "Charlie"  #=> "AlphaBravoCharlie"

文字列中に値を展開する

文字列の中に変数などの値を埋め込んで文字列を作りたいことがある。C言語のprintf()のフォーマット文字列のような昔ながらのスタイルと、 format() メソッドを使った新しいスタイルがある。

# 文字列として展開: %s
"value is %s" % "string"  #=> "value is string"
"value is %s" % 10  #=> "value is 10"
"value is %s" % 1.2  #=> "value is 1.2"
"value is %s" % ["a", "b"]  #=> 'value is ["a", "b"]'
"value is %s" % dict(a=1, b=2)  #=> "value is {'a': 1, 'b': 2}"

# 展開する値が複数ある場合はtupleにする
"values: %s and %s" % ("first", "second")  #=> "values: first and second"

# tuple自体を出力したい時は要素1のtupleにする
"value is %s" % (("a", "b"),)  #=> "value is ('a', 'b')"

# intとして展開: %d
"value is %d" % 123  #=> "value is 123"
"value is %04d" % 98  #=> "value is 0909" 4桁に満たない場合0を詰める

# floatとして展開: %f
"value is %f" % 1.23  #=> "value is 1.23"
"value is %.2f" % 10  #=> "value is 10.00"
"value is %06.2f" % 12.5  #=> "value is 012.50" 小数点以下は2桁表示, 全体で6文字に満たない場合ゼロ詰め
"value is %.1f" % 1.26  #=> "1.3" (1.25だと1.2のようで謎の丸め?)

その他にも16進数として展開する %x および %X などもある。(数値の扱いのページにも記述)

format()メソッドによる値の展開

展開する位置に {} を置いたテンプレート文字列に対して format() メソッドを呼ぶことで値を埋め込んだ文字列を作れる。

name = "python"
"name is {}".format(name)  #=> "name is python"

# 複数展開
"{} is {}".format("python", "snake")  #=> "python is snake"

# 整数の展開: 普通の展開の %04d のような表記が使える
"number is {:04d}".format(12)  #=> "number is 0012"

# 浮動小数点数の展開: 普通の展開の %06.2f のような表記が使える
"number is {:06.2f}".format(23.2)  #=> "number is 023.20"

# キーワード引数を使うこともできる
"{a}? {a}! {b}".format(a="hoge", b="moge")  #=> 'hoge? hoge! moge'

# dictのキーワード引数展開
keywords = dict(a="hoge", b="moge")
"{a}? {a}! {b}".format(**keywords)  #=> 'hoge? hoge! moge'

# キーワード引数とフォーマット指定子
"number is {num:04d}".format(num=12)  #=> 'number is 0012'

詳細は公式ドキュメントの書式指定ミニ言語仕様を参照。

フォーマット済み文字列リテラル

Python 3.6 で追加された。ふつうの文字列リテラルの前に f を置くとフォーマット済み文字列リテラルとして処理される。

hoge = "ほげ"
f"variable hoge is {hoge}"  #=> "variable hoge is ほげ"

# 整数の展開: %04d のような表記が使える
num = 12
f"num is {num:04d}"  #=> 'num is 0012'

# 少数の展開: %06.2f のような表記が使える
num2 = 23.2
f"num2 is {num2:06.2f}"

他にも :x:X で16進数のフォーマッティングができるなど高機能。詳細は公式ドキュメントの書式指定ミニ言語仕様を参照。

部分文字列が含まれているか検索

in 演算子でテストでき、結果を bool 型で得ることができる。

a = "hello"
test_result = "e" in a  #=> True

if "h" in a:
	print("found 'h' !")  #=> 出力される

test2 = "x" in a  #=> False

部分文字列の位置を探す

find() メソッドが使える。見つかった場合は見つかったインデックスを、見つからなかった場合は -1 が返ってくる。

s = "おいしい肉まんがあります"
idx = s.find("肉まん")
print(idx)  #=> 4

# s[4:7] から探す
s.find("ま", 4, 7)  #=> 5

複数の文字列を区切り文字を挟んで連結(join)

join() メソッドでlistやtupleに入ってる複数の文字列を連結できる。

parts = ["hop", "step", "jump"]
" => ".join(parts)  #=> "hop => step => jump"

# str以外は文字列に変換しないとjoinできない
numbers = [1, 2, 3]
",".join([str(n) for n in numbers])  #=> "1,2,3"

区切り文字で分割(split)

split() メソッドで分割できる。

s = "肉まん,あんまん,ピザまん"
s.split(",")  #=> ["肉まん", "あんまん", "ピザまん"]

正規表現で分割(re.split)

組み込みパッケージ re の関数 re.split() を使うと正規表現で文字列を分割できる。

re は Regular Expression の略だと思われる。

# re.split(pattern, string, maxsplit=0, flags=0)

import re
s = "2022-05-07 12:34:56"
re.split(r'[- :]', s)  #=> ['2022', '05', '07', '12', '34', '56']

# reオブジェクトを第一引数に指定することもできる。
pattern1 = re.compile(r'[- :]')
re.split(pattern1, s, 2)  #=> ['2022', '05', '07 12:34:56']  分割回数を指定

# flagsを使う
s2 = "?a?B?c?"
re.split(r'[a-z]', s2, flags=re.IGNORECASE)  #=> ['?', '?', '?', '?'] パターンはa-zだがBでも区切れている
re.split(r'[a-zA-Z]', s2)  # ↑はこのように書いても同じだが(個人的にはこちらが好み)

置換する(replace)

replace() メソッドで文字列に対して置換を行える。

#  aa を ?? に置き換える
s = "aabbaaa"
s.replace("aa", "??")  #=> "??bb??a" sは変化しない。置換された新しい文字列が作られて返される

正規表現で置換する(re.sub)

組み込みパッケージ re の関数 re.sub() を使うと正規表現で置換対象文字列のパターンを指定して置換を行える。

# re.sub(pattern, repl, string, count=0, flags=0)
#   pattern => 置き換えたい部分のパターン(reオブジェクト)
#   repl    => 置き換えて代わりに挿入する文字列 / またはマッチオブジェクトを引数に取り文字列を返す関数
#   string  => 置換を行う対象の文字列
#   count   => 置換する最大の回数。0ならすべて。たとえば2なら最大2箇所置換される。
#   flags   => re.IGNORECASE などの挙動制御フラグを指定できる。
#              ビット演算で複数のフラグを指定もできる:
#                re.IGNORECASE | re.DOTALL

import re

s = '2022-05-07 12:34:56'
re.sub(r'[- :]', '_', s)  #=> '2022_05_07_12_34_56'

# 第一引数にコンパイル済みパターン(reオブジェクト)を指定してもよい
pattern1 = re.compile(r'[- :]')
re.sub(pattern1, '_', s)  #=> '2022_05_07_12_34_56'

# 置換される文字列の内容に基づいて置き換える文字列を変えたいとき, 関数にする
def two_times(match_obj):
	match_s = match_obj.group(0)
	n = int(match_s)
	return str(n * 2)
re.sub(r'[0-9]+', two_times, '1 2 3')  #=> "2 4 6"

両端の空白・タブ・改行を削除

strip() メソッドで文字列の両端の空白・タブ・改行( \n\r も)を削除できる。第一引数に削除したい文字の集合を与えると空白以外も削除できる。


a = " a\r\n"
a.strip()  #=> "a" 左端の空白と、右端の \r\n が削除された

b = "\t\tb"
b.strip()  #=> "b" 左端のタブ2文字が削除された

# 削除する文字を指定
c = "aaab cd"
c.strip("acd")  #=> "b " スペースが残ってることに注意。 aとcとdだけが削除された。

左端の空白・タブ・改行を削除

lstrip() メソッドで左端のみを対象とした strip() を行える。

a = " a\r\n"
a.lstrip()  #=> "a\r\n"  右端の \r\n は削除されなかった。

b = "\t\tb"
b.lstrip()  #=> "b" 左端のタブ2文字が削除された。

# 削除する文字を指定
c = "aaab cd"
c.lstrip("acd")  #=> "b cd" 右端は対象にならない

右端の空白・タブ・改行を削除

rstrip() メソッドで右端のみを対象とした strip() を行える。

a = " a\r\n"
a.rstrip()  #=> " a"  右端の\r\nが削除され左端のスペースは残った

b = "\t\tb"
b.rstrip()  #=> "\t\tb"  左端のタブ2文字が削除されず残った

c = "aaab cd"
c.rstrip("acd")  #=> "aaab " 右端のcdが削除された(スペースが残っていることに注意)

数値を文字列化

str() で文字列にできる。2進数/8進数/16進数表記の文字列化については数値の扱いのページに記載した。

str(123)  #=> "123"
str(-12.345)  #=> "-12.345"

文字列を数値化

int()float() で数値化できる。

s1 = "123"
int(s1)  #=> 123 (int型)

s2 = "9.87"
float(s2)  #=> 9.87 (float型)

文字をすべて小文字/大文字にする

それぞれ lower() メソッド / upper() メソッドでできる。

s = "Hello"

# すべて小文字化
s.lower()  #=> "hello"

# すべて大文字化
s.upper()  #=> "HELLO"

先頭を大文字に、残りを小文字にする

capitalize() メソッドで先頭を大文字に、残りを小文字にした文字列を得られる。

s = "hEllO"
s.capitalize()  #=> "Hello"

特定の文字コードでエンコードしたバイト列(bytes)を得る

encode() メソッドでバイト列に変換できる。

s = "へび"
bytes_of_s = s.encode("utf-8")  #=> b'\xe3\x81\xb8\xe3\x81\xb3'

s.encode()  #=> 省略すると encode("utf-8") と同じ

# cp932(WindowsのShift-JIS)での「へび」のバイト列
s.encode("cp932")  #=> b'\x82\xd6\x82\xd1'

バイト列から特定のエンコードで解釈して文字列(str)型に変換する

バイト列( bytes 型)のメソッド decode() でエンコーディングを指定して文字列として解釈することができる。

# 
hebi_in_cp932 = b'\x82\xd6\x82\xd1'  #=> bytes型
hebi_in_cp932[0]  #=> 130  (1文字目ではなく1バイト目)
len(hebi_in_cp932)  #=> 4 (2文字ではなく4バイト)

hebi_str = hebi_in_cp932.decode('utf-8')  #=> "へび"
type(hebi_str)  #=> str
hebi_str[0]  #=> "へ"  (1文字目)
len(hebi_str)  #=> 2 (2文字)

アルファベットすべての文字種の定数がほしい

自分で書いてもいいが、組み込みパッケージ string便利な定数がある。

import string

# 小文字
string.ascii_lowercase  #=> "abcdefghijklmnopqrstuvwxyz"

# 大文字
string.ascii_uppercase  #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# 小文字 + 大文字
string.ascii_letters  #=> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

0から9までのすべての数字の文字種の定数がほしい

自分で書いてもいいが、組み込みパッケージ stringdigits という定数が使える。

import string

string.digits  #=> "0123456789"

# 8進数で使われる文字種(0-7)
string.octdigits  #=> "01234567"

# 16進数で使われる文字種(0-9, a-f, A-F)
string.hexdigits  #=> "0123456789abcdefABCDEF"

文字列先頭の特定の文字列を削除(removeprefix)

removeprefix() メソッドでできる。

Python3.9から追加された機能。

"GoodPython".removeprefix("Good")  #=> "Python"

文字列末尾の特定の文字列を削除(removesuffix)

removesuffix() メソッドでできる。

Python3.9から追加された機能。

"GoodPython".removesuffix("Python")  #=> "Good"

参考リンク