Pythonで文字列のリスト(配列)の条件を満たす要素を抽出、置換

文字列を要素とするリスト(配列)から、特定の条件を満たす文字列の要素のみを抽出したり、置換や変換などの処理をしたりして新たなリストを生成します。 リスト内包表記を使います。 ここでは、

リスト内包表記

について簡単に説明したあとで、

特定の文字列を含む(部分一致) / 含まない で抽出 特定の文字列を置換 特定の文字列で始まる / 始まらない で抽出 特定の文字列で終わる / 終わらない で抽出 大文字・小文字で判定し抽出 大文字・小文字を変換 英字か数字か判定し抽出 複数条件 正規表現

についてサンプルコードとともに説明します。 リスト内包表記を使ったリストの要素の抽出や置換・変換などの構文についての説明は

文字列を要素とするリストを数値のリストに変換したい場合は

なお、リストは異なる型のデータを格納可能で、厳密には配列とは異なります。メモリサイズやメモリアドレスを必要とするような処理や大規模なデータの数値計算処理などで配列を扱いたい場合はarray(標準ライブラリ)やNumPyを使います。

リスト内包表記

リストから新たなリストを生成する場合はリスト内包表記を使うとforループよりもシンプルに書けます。

[式 for 任意の変数名 in イテラブルオブジェクト if 条件式]

要素を条件式で選択するだけであれば式で処理することはないので、 [変数名 for 変数名 in 元のリスト if 条件式]

という形になります。 if 条件式をif not 条件式にすると否定になり、条件式を満たさない要素を抽出できます。

特定の文字列を含む(部分一致) / 含まない: in

特定の文字列 in 元の文字列で、元の文字列に特定の文字列が含まれるとTrueを返します。これを条件式とします。 inの否定はnot inを使います。

l = ['oneXXXaaa', 'twoXXXbbb', 'three999aaa', '000111222']

l_in = [s for s in l if 'XXX' in s]
print(l_in)
# ['oneXXXaaa', 'twoXXXbbb']

l_in_not = [s for s in l if 'XXX' not in s]
print(l_in_not)
# ['three999aaa', '000111222']

特定の文字列を置換

リストの要素の文字列を置換したい場合、リスト内包表記で各要素に文字列メソッドreplace()を使います。 置換対象の文字列がない場合はreplace()を適用しても変更しないので、if 条件式で要素を選択する必要はない。

l_replace = [s.replace('XXX', 'ZZZ') for s in l]
print(l_replace)
# ['oneZZZaaa', 'twoZZZbbb', 'three999aaa', '000111222']

特定の文字列を含む要素をまるごと置き換えたい場合はinで抽出して三項演算子で処理します。 三項演算子は真の値 if 条件式 else 偽の値という形で書きます。 リスト内包表記の式の部分を三項演算子とすれば問題ありません。

l_replace_all = ['ZZZ' if 'XXX' in s else s for s in l]
print(l_replace_all)
# ['ZZZ', 'ZZZ', 'three999aaa', '000111222']

特定の文字列で始まる / 始まらない: startswith()

文字列メソッドstartswith()は、文字列が引数に指定した文字列で始まるとTrueを返します。

l_start = [s for s in l if s.startswith('t')]
print(l_start)
# ['twoXXXbbb', 'three999aaa']

l_start_not = [s for s in l if not s.startswith('t')]
print(l_start_not)
# ['oneXXXaaa', '000111222']

特定の文字列で終わる / 終わらない: endswith()

文字列メソッドendswith()は、文字列が引数に指定した文字列で終わるとTrueを返します。

l_end = [s for s in l if s.endswith('aaa')]
print(l_end)
# ['oneXXXaaa', 'three999aaa']

l_end_not = [s for s in l if not s.endswith('aaa')]
print(l_end_not)
# ['twoXXXbbb', '000111222']

大文字・小文字で判定し抽出

文字列メソッドisupper(), islower()で文字列がすべて大文字か小文字かを判定できます。 メソッドの詳細は

l_lower = [s for s in l if s.islower()]
print(l_lower)
# ['three999aaa']

大文字・小文字を変換

すべての文字を大文字や小文字に変換したい場合は、文字列メソッドupper()やlower()を使います。そのほか、最初の一文字だけ大文字にするcapitalize()や、大文字と小文字を入れ替えるswapcase()などもあります。 メソッドの詳細は

上述の置換の例と同様に、条件を満たす要素のみ処理したい場合は三項演算子を使います。

l_upper_all = [s.upper() for s in l]
print(l_upper_all)
# ['ONEXXXAAA', 'TWOXXXBBB', 'THREE999AAA', '000111222']

l_lower_to_upper = [s.upper() if s.islower() else s for s in l]
print(l_lower_to_upper)
# ['oneXXXaaa', 'twoXXXbbb', 'THREE999AAA', '000111222']

英字か数字か判定し抽出

文字列メソッドisalpha()やisnumeric()で、文字列がすべて英字か数字かなどを判定できます。詳細は

l_isalpha = [s for s in l if s.isalpha()]
print(l_isalpha)
# ['oneXXXaaa', 'twoXXXbbb']

l_isnumeric = [s for s in l if s.isnumeric()]
print(l_isnumeric)
# ['000111222']

複数条件

リスト内包表記の条件式の部分は複数条件にすることもできます。複数の条件式をandやorでつなげれば問題ありません。否定notも使えます。 三つ以上の条件式を使う場合は順番によって結果が異なるので、まとまりごとに()で囲んでおいたほうが無難。

l_multi = [s for s in l if s.isalpha() and not s.startswith('t')]
print(l_multi)
# ['oneXXXaaa']

l_multi_or = [s for s in l if (s.isalpha() and not s.startswith('t')) or ('bbb' in s)]
print(l_multi_or)
# ['oneXXXaaa', 'twoXXXbbb']

正規表現

正規表現を使うと自由度の高い処理ができます。

re.match()がマッチしたときに返すmatchオブジェクトを条件式で評価すると常にTrueと判定されます。マッチしない場合は条件式でFalseとなるNoneを返すので、正規表現にマッチする要素のみを抽出する場合は、これまでのようにリスト内包表記の条件式の部分にre.match()を適用すれば問題ありません。

import re

l = ['oneXXXaaa', 'twoXXXbbb', 'three999aaa', '000111222']

l_re_match = [s for s in l if re.match('.*XXX.*', s)]
print(l_re_match)
# ['oneXXXaaa', 'twoXXXbbb']

正規表現にマッチした部分を置換するre.sub()も便利です。マッチした要素のみを抽出して置換する場合はif 条件式を追加すれば問題ありません。

l_re_sub_all = [re.sub('(.*)XXX(.*)', r'\2---\1', s) for s in l]
print(l_re_sub_all)
# ['aaa---one', 'bbb---two', 'three999aaa', '000111222']

l_re_sub = [re.sub('(.*)XXX(.*)', r'\2---\1', s) for s in l if re.match('.*XXX.*', s)]
print(l_re_sub)
# ['aaa---one', 'bbb---two']
Last Updated: 6/26/2019, 10:34:03 PM