python globでディレクトリ内のファイル一覧を取得する

久々に画像処理をしようと思い、pythonでディレクトリ内のファイル一覧を取得しようとしたのですが、
その際にハマったので少しメモしておきます。

pythonで日本語のディレクトリやファイルを扱うのって少し癖がありますよね。

結構皆さん躓くのではないでしょうか。

やりたいこと

このような階層になったフォルダがあった時に、この”[20190401] 写真”というフォルダを渡して、
そのフォルダの中身のリストを取得したい。

“[20190401] 写真” これから

[“/dir/dir/dir/IMG_0271.jpg”,
“/dir/dir/dir/IMG_0272.jpg”,
“/dir/dir/dir/IMG_0273.jpg”,
“/dir/dir/dir/IMG_0274.jpg”]

こういうリストを得たいというわけだ。

globを使う

基本的にこのように使います。

#!/usr/bin/python

import glob
list = glob.glob( "/path/to/directory/*" )

*アスタリスクはワイルドカードです。
これで、/path/to/tirectory/内の一覧を取得できるわけです。

globのワイルドカード

以下のワイルドカードを使用することができます。

*0文字以上の任意の文字列にマッチ
?任意の一文字にマッチ
[abc]かっこ[]内で指定された一文字にマッチ   ( “a” or “b” or “c” )
[0-9]かっこ[]内で指定された範囲内の一文字にマッチ   ( 0, 1, … , 9 )

ディレクトリ内を検索し、特定の拡張子だけ抜いてくる

例えば、画像だけを探してリストアップするとか。

list = []
directory = "/path/to/directory"
target_extension = [ ".png", ".jpg" ]
for target in target_extension:
    path_list.extend( glob.glob( directory + "/*" + target ) )

こうやって拡張子を指定してあげれば、その拡張子のファイルだけ抜き出すことができます。

注意(私がハマったこと)

勘のいい方はお気づきかもしれませんが、
先ほどの”[20190401] 写真”というディレクトリの中身をリストアップするに当たって、

ディレクトリの ”[20190401]” ここの部分が上記のワイルドカードに当てはまるため、
正しく検索できていませんでした。

[ ]がワイルドカードの検索に引っかからないようにエスケープ

そこで、[ ] このかっこが上記のワイルドカード検索に引っかからないようにエスケープする関数を作成します。

# escape function for glob
def escapeForGlob( input_str ):
    # convert [ -> [[] , ] -> []]
    escaped_str = input_str.replace("[","¥¥[").replace("]","¥¥]")
    escaped_str = escaped_str.replace("¥¥[","[[]").replace("¥¥]","[]]")
    return escaped_str

このような関数を作成します。かっこ自体をワイルドカードの検索の中に入れてしまいます。 [ [ ]
ここでも少しポイントが。

この関数、わざわざかっこの置き換えを

[   →   \[   →   [[]     ,     ]   →   \]   →   []]

このように二段階で行なっています。直接

[   →   [[]     ,     ]   →   []]

これでいいじゃんか。と思います・・・が、
直接変換すると、、、

[20190401] 写真   →   [[]20190401] 写真(左かっこの置換)   →   [[[]]20190401[]](右かっこの置換)

こうなってしまいます。

最終的に、、、

最終的にこんなコードになりました。

#!/usr/bin/python import glob

# escape function for glob
def escapeForGlob( input_str ): # かっこをエスケープする関数
    # convert [ -> [[] , ] -> []]
    escaped_str = input_str.replace("[","¥¥[").replace("]","¥¥]")
    escaped_str = escaped_str.replace("¥¥[","[[]").replace("¥¥]","[]]")
    return escaped_str target_dir = "/path/to/target_dir/[20180401] 写真"

list = glob.glob( escapeForGlob( target_dir ) + "/*" ) # かっこをエスケープ後、ディレクトリ内をワイルドカードで
print( list )
# output :
# ["IMG_0271.jpg", "IMG_0272.jpg", "IMG_0273.jpg", "IMG_0274.jpg"]

皆さんも、pythonでディレクトリ内をリストアップする際にglob関数で躓かないことを願っています。

ではでは。