Pythonで文字列を置換(replace, translate, re.sub, re.subn)

Pythonで文字列を置換する方法について説明します。

文字列を指定して置換: replace() 最大置換回数を指定: 引数count 複数の文字列を置換 改行文字を置換 複数の文字を指定して置換: translate() 正規表現で置換: re.sub(), re.subn() 複数の文字列を同じ文字列に置換 マッチした部分を使って置換 置換した部分の個数を取得 位置を指定して置換・挿入: スライス

大文字と小文字を変換する場合は専用のメソッドが用意されています。

文字列を指定して置換: replace

文字列を指定して置換する場合は文字列(str型)のreplace()メソッドを使います。

  1. 組み込み型 str.replace() — Python 3.6.5 ドキュメント

第一引数に置換元文字列、第二引数に置換先文字列を指定します。

s = 'one two one two one'

print(s.replace(' ', '-'))
# one-two-one-two-one

置換先文字列を空文字列''にすると削除されます。

print(s.replace(' ', ''))
# onetwoonetwoone

最大置換回数を指定: 引数count

第三引数countで最大置換回数を指定できます。最大置換回数を超えると置換されません。 print(s.replace('one', 'XXX'))

XXX two XXX two XXX

print(s.replace('one', 'XXX', 2))

XXX two XXX two one

複数の文字列を置換

複数の文字列を同じ文字列に置換する場合は後述の正規表現を使います。 複数の文字列をそれぞれ別の文字列に置換するためのメソッドは用意されていません。 replace()を繰り返し適用することで複数の文字列を置換できます。

print(s.replace('one', 'XXX').replace('two', 'YYY'))
# XXX YYY XXX YYY XXX

ただ単にreplace()を順番に呼んでいるだけなので、はじめの置換先文字列が以降の置換元文字列を含んでいる場合は、はじめの置換先文字列も置換されます。順番に気をつけてください。

print(s.replace('one', 'XtwoX').replace('two', 'YYY'))
# XYYYX YYY XYYYX YYY XYYYX

print(s.replace('two', 'YYY').replace('one', 'XtwoX'))
# XtwoX YYY XtwoX YYY XtwoX

複数の文字(長さ1の文字列)を置換する場合はtranslate()メソッドが使えます。後述します。

改行文字を置換

改行文字が一種類だけの場合はreplace()の第一引数に指定すれば問題ありません。

s_lines = 'one\ntwo\nthree'
print(s_lines)
# one
# two
# three

print(s_lines.replace('\n', '-'))
# one-two-three

Macを含むUnix系OSで使われる改行文字\n(LF)とWIndows系OSで使われる改行文字\r\n(CR+LF)が混在している場合は注意が必要。 \r\nの中に\nが含まれているので順番によっては所望の結果が得られない。

s_lines_multi = 'one\ntwo\r\nthree'
print(s_lines_multi)
# one
# two
# three

print(s_lines_multi.replace('\r\n', '-').replace('\n', '-'))
# one-two-three

print(s_lines_multi.replace('\n', '-').replace('\r\n', '-'))
# -three

各種の改行文字で分割したリストを返すsplitlines()とリストを文字列に連結するjoin()メソッドを利用することもできます。 どんな改行文字が含まれているかわからない場合はこの方法が安全。

print(s_lines_multi.splitlines())
# ['one', 'two', 'three']

print('-'.join(s_lines_multi.splitlines()))
# one-two-three

文字列の分割については

改行に関するそのほかの処理は

複数の文字を指定して置換: translate

複数の文字(長さ1の文字列)を指定して置換する場合は文字列(str型)のtranslate()メソッドを使います。

  1. 組み込み型 str.translate() — Python 3.6.5 ドキュメント

translate()に指定する変換テーブルはstr.maketrans()関数で作成します。

  1. 組み込み型 str.maketrans() — Python 3.6.5 ドキュメント

str.maketrans()関数には置換元文字をキー、置換先文字列を値とする辞書を指定します。 置換元文字は1文字(長さ1の文字列)でなければならない。置換先文字列は文字列またはNoneで、Noneの場合は対応する置換元文字が削除されます。

s = 'one two one two one'

print(s.translate(str.maketrans({'o': 'O', 't': 'T'})))
# One TwO One TwO One

print(s.translate(str.maketrans({'o': 'XXX', 't': None})))
# XXXne wXXX XXXne wXXX XXXne

str.maketrans()関数には辞書ではなく3つの文字列を引数として指定することもできます。 第一引数には置換元文字を連結した文字列、第二引数には置換先文字を連結した文字列、第三引数には削除する置換元文字列を連結した文字列を指定します。

print(s.translate(str.maketrans('ow', 'XY', 'n')))
# Xe tYX Xe tYX Xe

この場合、第一引数と第二引数の文字列の長さは一致している必要があり、置換先文字列に長さ2以上の文字列を指定できません。

# print(s.translate(str.maketrans('ow', 'XXY', 'n')))
# ValueError: the first two maketrans arguments must have equal length

正規表現で置換: re.sub, re.subn

replace()やtranslate()では置換元文字列に完全一致した場合に置換されます。 完全一致ではなく正規表現にマッチした文字列を置換したい場合はreモジュールのsub()関数を使います。 標準ライブラリのreモジュールをインポートして使います。標準ライブラリなので追加のインストールは不要。

6.2. re.sub() — 正規表現操作 — Python 3.6.5 ドキュメント

re.sub()では第一引数に正規表現パターン、第二引数に置換先文字列、第三引数に処理対象の文字列を指定します。

import re

s = 'aaa@xxx.com bbb@yyy.com ccc@zzz.com'

print(re.sub('[a-z]*@', 'ABC@', s))
# ABC@xxx.com ABC@yyy.com ABC@zzz.com


replace()と同じく第四引数countに最大置換回数を指定できます。
print(re.sub('[a-z]*@', 'ABC@', s, 2))
# ABC@xxx.com ABC@yyy.com ccc@zzz.com

reモジュールのその他の関数、正規表現オブジェクトの生成方法などは

複数の文字列を同じ文字列に置換

正規表現に詳しくなくても覚えておくと便利なのが以下の2つ。 大括弧[]で囲むとその中の任意の一文字にマッチします。複数の異なる文字を同じ文字列に置換する場合に使います。

print(re.sub('[xyz]', '1', s))
# aaa@111.com bbb@111.com ccc@111.com

パターンを|で区切るといずれかのパターンにマッチします。各パターンには正規表現の特殊文字を使うことももちろん可能だが、文字列をそのまま指定しても問題ありません。複数の異なる文字列を同じ文字列に置換する場合に使います。

print(re.sub('aaa|bbb|ccc', 'ABC', s))
# ABC@xxx.com ABC@yyy.com ABC@zzz.com

マッチした部分を使って置換

パターンの一部を()で囲むと、置換先文字列の中で()で囲んだ部分にマッチする文字列を使用することができます。

print(re.sub('([a-z]*)@', '\\1-123@', s))
# aaa-123@xxx.com bbb-123@yyy.com ccc-123@zzz.com

print(re.sub('([a-z]*)@', r'\1-123@', s))
# aaa-123@xxx.com bbb-123@yyy.com ccc-123@zzz.com

\1が()にマッチした部分に対応しています。()が複数ある場合は、\2, \3...のようにして使います。 ''または""で囲まれた通常の文字列だと\1のように\をエスケープする必要があるが、r''のように先頭にrをつけるraw文字列の場合は\1で問題ありません。

置換した部分の個数を取得

re.subn()関数は置換処理された文字列と置換した部分の個数とのタプルを返します。

6.2. re.subn() — 正規表現操作 — Python 3.6.5 ドキュメント

t = re.subn('[a-z]*@', 'ABC@', s)
print(t)
# ('ABC@xxx.com ABC@yyy.com ABC@zzz.com', 3)

print(type(t))
# <class 'tuple'>

print(t[0])
# ABC@xxx.com ABC@yyy.com ABC@zzz.com

print(t[1])
# 3

位置を指定して置換・挿入: スライス

位置を指定して置換するメソッドは無いが、スライスで分割して任意の文字列と連結することで指定した位置が置換された新たな文字列を作成できます。

s = 'abcdefghij'

print(s[:4] + 'XXX' + s[7:])
# abcdXXXhij

文字列の長さ(文字数)はlen()で取得できるので以下のようにも書けます。こちらのほうが間違いは少ない。

s_replace = 'XXX'
i = 4

print(s[:i] + s_replace + s[i + len(s_replace):])
# abcdXXXhij

単純に分割した文字列の間に別の文字列を連結しているだけなので文字数が一致している必要はない。

print(s[:4] + '-' + s[7:])
# abcd-hij

文字列の任意の位置に別の文字列を挿入して新たな文字列を作成することもできます。

print(s[:4] + '+++++' + s[4:])
# abcd+++++efghij
Last Updated: 6/26/2019, 10:34:03 PM