note.nkmk.me

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

Date: 2018-05-31 / tags: Python, 文字列操作, 正規表現

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

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

大文字と小文字を変換する場合は専用のメソッドが用意されている。以下の記事を参照。

スポンサーリンク

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

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

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

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()の第一引数に指定すればOK。

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()メソッドを使う。

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

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モジュールをインポートして使う。標準ライブラリなので追加のインストールは不要。

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

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

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でOK。

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

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

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

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

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

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

print(s[:4] + '+++++' + s[4:])
# abcd+++++efghij

スライスについての詳細は以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事