検索
連載

[解決!Python]文字列から部分文字列を削除する基本的なやり方とは(replace/translate/strip/removeprefix/removesuffixメソッド、re.sub関数)解決!Python

文字列が持つ各種メソッドやreモジュールのsub関数を使って、文字列内にある特定の文字列を削除する方法を紹介する。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「解決!Python」のインデックス

連載目次

# 定型の部分文字列を削除:replaceメソッド
s1 = 'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html'
s2 = s1.replace('https://', ''# 'https://'を削除(空文字列に置換)
print(s2)  # www.atmarkit.co.jp/ait/articles/2101/19/news022.html

# 特定の文字群を一括して削除:translateメソッド
s1 = 'name: [shinji+kawasaki], height: 172, weight: 80'
tbl = str.maketrans('+', ' ', ' []')
s2 = s1.translate(tbl)
print(s2)  # name:shinji kawasaki,height:172,weight:80
s3 = s2.split(',')
print(s3)  # ['name:shinji kawasaki', 'height:172', 'weight:80']
d = dict([item.split(':') for item in s3])
print(d)  # {'name': 'shinji kawasaki', 'height': '172', 'weight': '80'}

# 文字列の先頭/末尾にある空白文字を削除:strip/lstrip/rstripメソッド
s1 = '  ==** sample text **==  '
s2 = s1.strip()  # 文字列s1の先頭/末尾にある空白文字を削除
print(s2)  # ==** sample text **==

s2 = s1.strip(' ='# 引数に指定した文字を文字列s1の先頭/末尾から削除
print(s2)  # ** sample text **

s2 = s1.lstrip(' =*'# 引数に指定した文字を文字列s1の先頭から削除
s3 = s1.rstrip(' =*'# 引数に指定した文字を文字列s1の末尾から削除
print('lstrip:', s2)  # lstrip: sample text **==
print('rstrip:', s3)  # rstrip:   ==** sample text

# 特定のプレフィックス/サフィックスを削除:removeprefix/removesuffixメソッド
s1 = '_start_ sample text _end_'
s2 = s1.removeprefix('_start_'# 文字列が'_start_'で始まっていれば、それを削除
print(s2)  #  sample text _end_

s2 = s1.removesuffix('_end_'# 文字列が'_end_'で終わっていれば、それを削除
print(s2)  # _start_ sample text

# 正規表現を使う
import re
s1 = 'foo bar baz foo'
s2 = re.sub('foo', '', s1)  # 削除したい文字列/空文字列/対象の文字列
print(s2)  #  bar baz

s2 = re.sub(' *foo *', '', s1)  # 'foo'の前後に空白文字があればそれも一緒に削除
print(s2)  # bar baz


定型の部分文字列を削除する:replaceメソッド

 文字列のreplaceメソッドは、文字列中で指定したものを別の文字列に置き換えた新しい文字列を作成するが、置換後の文字列として空文字列を指定することで、指定した文字列を削除できる。一定のフォーマットを持つ文字列を順次処理して、特定部分を取り除く(残りの部分を抽出する)ようなときにはreplaceメソッドが便利だろう。

 以下に例を示す。

s1 = 'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html'
s2 = s1.replace('https://', ''# 'https://'を削除(空文字列に置換)
print(s2)  # www.atmarkit.co.jp/ait/articles/2101/19/news022.html

url_list = [
  'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html',
  'https://www.atmarkit.co.jp/ait/articles/2101/20/news036.html'
]

stripped_url_list = []
for url in url_list:
  tmp = url.replace('https://', '')
  stripped_url_list.append(tmp)

# stripped_url_list = [url.replace('https://', '') for url in url_list]


 最初の例では、文字列'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html'を対象に、置換前の文字列に'https://'として、置換後の文字列に空文字列を指定して、replaceメソッドを呼び出している。置換後の文字列が空文字列なので、置換前の文字列'https://'が削除され、'www.atmarkit.co.jp/ait/articles/2101/19/news022.html'が返送されている。ここでは示さないが、削除(置換)を実行する回数を第3引数に指定することも可能だ。

 2つ目の例は、1つ目の例をforループ(あるいはコメントにあるようにリスト内包表記)で処理する例だ。

 replaceメソッドでは一度に1つの文字列の置換しか行えない。1つの文字列に対して、置換したい文字列が複数含まれているようなときには、replaceメソッドを繰り返し実行する。

s1 = 'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html'
s2 = s1.replace('https://', '').replace('.html', ''# replaceメソッドを連鎖
print(s2)  # www.atmarkit.co.jp/ait/articles/2101/19/news022


特定の文字群を一括して削除する:translateメソッド

 今見たように、replaceメソッドを連鎖させることで置換を複数回行える。が、文字列に含まれる何種類かの文字(記号など)を置換したり削除したりしたいのであれば、replaceメソッドを連鎖させるよりもtranslateメソッドを使った方がスッキリとコードを書けるかもしれない。

 translateメソッドは文字列に含まれる何かの1文字を、別の文字列または文字に変換するものだ。どの文字をどんな文字列(文字)に変換するかはstr.maketransスタティックメソッドを使って作成する「変換テーブル」に記述して、それを使ってtranslateメソッドを呼び出す。これについては「[解決!Python]文字列を置換するには(replace/translate/expandtabsメソッド)」も参照のこと。

 あまりよい例ではないが(恣意(しい)的な例だが)、'name: [shinji+kawasaki], height: 172, weight: 80'という文字列があったとしよう。これを加工して、辞書に{'name': 'shinji kawasaki', 'height': 172, 'weight': 80}のように登録したいとする。そのためには次のような手順を踏むことになるだろう。

  1. 空白文字と大かっこ「[]」を削除する
  2. 加算記号「+」を空白文字に置換する
  3. カンマ「,」で区切って'キー:値'という文字列を要素とするリストを作成する
  4. できたリストの要素をコロン「:」で区切り、[キー,値]というリストを要素とするリストを作成して、それをdict関数に渡す

 これを実際のコードにしたのが以下だ。

s1 = 'name: [shinji+kawasaki], height: 172, weight: 80'
tbl = str.maketrans('+', ' ', ' []')
s2 = s1.translate(tbl)
print(s2)  # name:shinji kawasaki,height:172,weight:80
s3 = s2.split(',')
print(s3)  # ['name:shinji kawasaki', 'height:172', 'weight:80']
d = dict([item.split(':') for item in s3])
# d = {k: v for k, v in [item.split(':') for item in s3]}
print(d)  # {'name': 'shinji kawasaki', 'height': '172', 'weight': '80'}


 str.maketransスタティックメソッドでは、上記の1と2の処理をまとめて行っている。つまり、第1引数に'+'を、第2引数に' 'を指定することで加算記号を空白文字に変換して、第3引数には' []'を指定することで、元の文字列からそれらを一括で削除するような変換テーブルを作成している。この変換テーブルを使ってtranslateメソッドを呼び出すことで余計な空白を含まない文字列ができるので、次にカンマを区切りとして、その文字列をリストへ分割する。できたリストは['name:shinji kawasaki', 'height:172', 'weight:80']のようになっているので、今度はリスト内包表記を使ってその各要素をコロンで分割し、2要素のリスト(['name', 'shinji kawasaki']など)を要素とするリストを作成して、それをdict関数に渡すことで辞書を作成している。

 このように、文字列に含まれる記号類の変換や削除をまとめて行えるので、覚えておくとよいだろう。

文字列の先頭/末尾にある空白文字を削除:strip/lstrip/rstripメソッド

 文字列の先頭/末尾にある空白文字(や特定の文字)を削除するには、strip/lstrip/rstripメソッドが使える。機械的に入手した、あるいは不定形なフォーマットで入力された文字列では、ほしい文字列の前後に空白文字がくっついていることもある。そうした場合には、これら3つのメソッドで簡単に空白文字を取り除ける。

 引数を指定せずにこれらのメソッドを呼び出せば、stripメソッドでは文字列の先頭/末尾から、lstripメソッドでは文字列の先頭から、rstripメソッドでは文字列の末尾から空白文字が削除される。

 以下に例を示す。

s1 = '  ==** sample text **==  '

s2 = s1.strip()  # 文字列s1の先頭/末尾にある空白文字を削除
print(s2)  # ==**_sample_text_**==
print(s2.replace(' ', '_'))  # ==**_sample_text_**==(確認用)

s2 = s1.lstrip()  # 文字列s1の先頭にある空白文字を削除
print(s2)  # ==** sample text **== 
print(s2.replace(' ', '_'))  # ==**_sample_text_**==__(確認用)

s2 = s1.rstrip()  # 文字列s1の末尾にある空白文字を削除
print(s2)  #   ==** sample text **==
print(s2.replace(' ', '_'))  # __==**_sample_text_**==(確認用)


 ここでは文字列' ==** sample text **== 'を元の文字列とする。3つのメソッド呼び出しでは引数を指定していないので、stripメソッドは文字列の先頭/末尾にある空白文字を、lstripメソッドは文字列の先頭にある空白文字を、rstripメソッドは文字列の末尾にある空白文字を削除する。

 それぞれのメソッドの戻り値に対して、空白文字をアンダースコアに変換した結果も同時に表示するようにしているので、結果を確認してほしい。

 これらのメソッドは多くの場合、空白文字を取り除くために使われるが、引数を指定することで、それに含まれている文字を一括して(文字列の先頭/末尾から)取り除くのにも使える。

s1 = '  ==** sample text **==  '

s2 = s1.strip(' ='# 引数に指定した文字を文字列s1の先頭/末尾から削除
print(s2)  # ** sample text **

s2 = s1.lstrip(' =*'# 引数に指定した文字を文字列s1の先頭から削除
s3 = s1.rstrip(' =*'# 引数に指定した文字を文字列s1の末尾から削除
print('lstrip:', s2)  # lstrip: sample text **==
print('rstrip:', s3)  # rstrip:   ==** sample text


 ここでは、3つのメソッドに引数として文字列' ='を指定している。これにより、文字列の先頭/末尾に含まれている空白文字と等号「=」が削除されるようになる。

 3つのメソッドに引数を指定したときには、それは削除したい文字の集合として解釈されることには注意が必要だ。上の例では引数には文字列' ='を指定しているが、これは「空白文字+等号」という文字の並びを削除するのではなく、「文字列の先頭/末尾にある空白文字と等号は全て削除する」という意味だ。

 そのため、これらのメソッドが自分の想定とは異なる振る舞いをすることもある。以下はその例だ。

s1 = 'test.txt'
s2 = s1.rstrip('.txt'# 文字列s1から拡張子を削除するつもり
print(s2)  # tes


 文字列s1には'test.txt'という文字列(恐らくはファイル名)が代入され、s2にはその拡張子である'.txt'をrstripメソッドで削除したものを代入しようとしている。しかし、これを実行すると、「tes」と表示されてしまう。rstripメソッドに渡した文字列'.txt'はあくまでも削除したい文字の集合であり、rstripメソッドは文字列末尾にある文字「.」「t」「x」「t」を全て取り除いてしまう。よって、'.txt'の直前にある文字't'まで削除されてしまったということだ。

 こうした想定外の削除が発生しないようにするには、以下で紹介する2つのメソッドを使用する。

特定のプレフィックス/サフィックスを削除:removeprefix/removesuffixメソッド

 removeprefix/removesuffixメソッドは、文字列が特定のプレフィックスで始まっているか(removeprefix)、特定のサフィックスで終わっていれば(removesuffix)、それらを文字列から取り除くという処理を行う。なお、これらのメソッドがサポートされているのはPython 3.9以降である点には注意すること。

 以下に例を示す。

s1 = '_start_ sample text _end_'
s2 = s1.removeprefix('_start_'# 文字列が'_start_'で始まっていれば、それを削除
print(s2)  #  sample text _end_

s2 = s1.removesuffix('_end_'# 文字列が'_end_'で終わっていれば、それを削除
print(s2)  # _start_ sample text


 これらのメソッドを使えば、上のrstripメソッドの例で見たような想定外の振る舞いを避けられるはずだ。

s1 = 'test.txt'
s2 = s1.removesuffix('.txt'# 文字列s1から拡張子を削除するつもり
print(s2)  # test


 また、冒頭のreplaceメソッドの例のような定型の文字列で始まり、定型の文字列で終了している文字列から、それらを削除するのであれば、replaceメソッドではなく今見た2つのメソッドを使ってもよい。

s1 = 'https://www.atmarkit.co.jp/ait/articles/2101/19/news022.html'
s2 = s1.removeprefix('https://').removesuffix('.html'
print(s2)  # www.atmarkit.co.jp/ait/articles/2101/19/news022


 この例では、removeprefixメソッドとremovesuffixメソッドの呼び出しを連鎖させている。replaceメソッドとの使い分けのポイントは、もちろん文字列が特定の文字列で始まっていたり、終わっていたりするかどうかだが、これらを使うことで何をしているのかがコード上でハッキリと分かるというメリットもあるだろう。

正規表現を使う

 最後に正規表現を使った簡単な例も紹介しておこう。Pythonには正規表現を取り扱うためのreモジュールが標準で添付されている(「re」は「regular expression」を省略したもの)。このモジュールで定義されているre.sub関数を使っても文字列から特定の部分文字列を削除できる。この関数は、指定したパターンを文字列から検索し、それを別の表現に置き換えるが、置換後の表現を空文字列とすれば元のパターンが削除される。

 以下に例を示す(第4引数には置換を行う回数を、第5引数には正規表現マッチングに関するフラグを指定できるが、ここでは取り上げない)。

import re
s1 = 'foo bar baz foo'
s2 = re.sub('foo', '', s1)  # 削除したい文字列/空文字列/対象の文字列
print(s2)  #  bar baz

s2 = re.sub(' *foo *', '', s1)  # 'foo'の前後に空白文字があればそれも一緒に削除
print(s2)  # bar baz


 re.sub関数には第1引数として置換前のパターン、第2引数に置換後の表現、第3引数に処理対象の文字列を与える。1つ目の例では、第1引数には単純な文字列'foo'を、第2引数には(削除するので)空文字列を、第3引数には文字列'foo bar baz foo'を指定している。これにより、文字列'foo bar baz foo'から'foo'が削除された新しい文字列が得られる。

 次の例では、第1引数に' *foo *'を与えている。これは非常に単純な正規表現で、fooの前後に0個以上の空白文字があれば、それも削除(置換)の対象とすることを表している。それ以外の引数は1つ目の例と同様だ。そのため、1つ目の例とは異なり、戻り値の文字列の前後に余計な空白文字が含まれないようになっている。正規表現を使うことでより柔軟な形で何を削除して、何を削除しないのかを短いコードで表現できる。

 なお、reモジュールの詳細についてはPython公式サイトの「re --- 正規表現操作」を、Pythonの正規表現については「正規表現 HOWTO」を参照されたい。

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る