###前提・実現したいこと
以前こちらで大量にあるCSVファイルの中から任意のデータを抽出する方法を質問しました。
その際は glob を使って ディレクトリ内のデータを一括で取得する方法を教わりました。
その延長で扱うデータファイルの数自体が更に増えてしまい、
すべてのファイルを一気に取得すること自体が効率的でなくなってしまいました。
前提として、ファイル名が含んでいる任意の単語を入力して
必要なファイルの候補を絞り込むフィルタ機能を作成したいが、
今後さらに増えることも予測して 汎用性の高い データファイルの 選択機能を用意したい、
と考えています。
###発生している問題・エラーメッセージ
現状は 1単語だけの候補絞り込みができていますが、
複数の単語でのand検索、
または複数単語で1つでも該当するものを見つけるor検索
的なものへの発展ができないか検討しています。
###該当のソースコード・試したこと
具体的に、指定ディレクトリ内のCSVファイル を すべて取り込もうとした際、
import glob files = glob.glob('dir/*.csv')
としていましたが、
import glob word = input('ファイル名 の 検索ワードを入力 (入力ない場合は全読込み) : ') files = glob.glob('dir/*'+ word +'*.csv')
と変えることで、簡単ですが1回だけ任意の単語を入力できるようにするだけで
大分候補を絞れて使いやすくはなりました。
ですが、これだと
・2つ以上の単語を入力してすべてに該当するファイルの絞り込み (and)
・2つ以上の単語を入力してどれか1つでも単語に該当するファイルの検索 (or)
が実現できないため、
もっと良い方法はないものか考えています。
###補足情報(言語/FW/ツール等のバージョンなど)
Python 3.6.2
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
ベストアンサー
glob.iglobを用いるとメモリを食いませんし、融通が効くかもしれません。
以下、即興で書いた使用例です。
Python
1import glob 2 3def is_img_file(file): 4 if file.endswith('.png'): return True 5 if file.endswith('.jpg'): return True 6 return False 7 8img_files = [file for file in glob.iglob('*.*') if is_img_file(file)]
かなり泥臭く、もっとすっきり書く方法もあるような気もしますが、小回りは利くかと思います。
例をちょっと改良してみました。
Python
1import glob 2 3search_words = input('input words: ').split() 4search_mode = input('search mode(OR/AND): ') 5 6def make_is_target(words): 7 def is_target_or(filename): 8 return any(word in filename for word in words) 9 10 def is_target_and(filename): 11 return all(word in filename for word in words) 12 13 return is_target_or, is_target_and 14 15 16if search_mode == 'OR': 17 is_target = make_is_target(search_words)[0] 18elif search_mode == 'AND': 19 is_target = make_is_target(search_words)[1] 20else: 21 is_target = lambda _: False 22 23target_files = [file for file in glob.iglob('*.*') if is_target(file)] 24print(target_files)
実行例
>python hoge.py input words: java py search mode(OR/AND): OR ['Bikkuri.java', 'classtree.py', 'hoge.py', 'Main.java'] >python hoge.py input words: java py search mode(OR/AND): AND [] >python hoge.py input words: hoge py search mode(OR/AND): AND ['hoge.py']
投稿2017/12/14 15:59
編集2017/12/14 17:08総合スコア35660
0
LouiS0616さんの改良コードに、無駄な機能を追加してみました。
- サーチモードのデフォルト(OR)を追加しました
- サーチモード選択をcase-insensitiveにしました
- make_is_targetの移植性を高めました
python
1import glob 2 3files = glob.glob('*.*') 4 5search_words = input('input words: ').split() 6search_mode = input('search mode(OR/AND default:OR): ') or 'OR' 7 8def make_is_target(words, selection_rule=None): 9 if selection_rule is None: 10 print('WARNING: UNKNOWN search mode') 11 return lambda _: False 12 assert(selection_rule in [any, all]) 13 def is_target(filename): 14 return selection_rule(word in filename for word in words) 15 return is_target 16 17if search_mode.upper() == 'AND': 18 is_target = make_is_target(search_words, selection_rule=all) 19elif search_mode.upper() != 'OR': 20 is_target = make_is_target(search_words) 21else: 22 is_target = make_is_target(search_words, selection_rule=any) 23 24target_files = [file for file in files if is_target(file)] 25print(target_files)
LinuxやMacならシェルに頑張っていただくこともできます。
python
1import subprocess 2run = subprocess.getoutput 3 4search_words = input('input words: ').split() 5path = '.' 6 7target_files = run('ls {0} | grep -E "{1}"'.format(path, '|'.join(search_words))).split() # OR 8 9print(target_files) 10 11target_files = run('ls {0} | {1}'.format(path, ' | '.join(map('grep {0}'.format, search_words)))).split() # AND 12 13print(target_files)
投稿2017/12/14 19:47
編集2017/12/15 10:21総合スコア8560
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
勉強中の人間としてはみなさんの回答にそれぞれうろこが落ちる思いです。
が、ここで敢えて違う方法に挑戦してみたいと思います。
python
1import glob 2import re 3 4def inc_all(reglist, filelist): 5 rr = "^" 6 for i in reglist: 7 rr = rr + "(?=.*" + i + ")" 8 r = re.compile(rr) 9 return([i for i in filter(r.search, filelist)]) 10 11def inc_one(reglist, filelist): 12 rr = "(" + '|'.join(reglist) + ")" 13 r = re.compile(rr) 14 return([i for i in filter(r.search, filelist)]) 15 16files = glob.glob("*.*") 17 18print(files) 19print("#1", inc_all(["pl","test"], files)) 20print("#2", inc_one(["pl","test"], files)) 21print("#3", inc_all(["(pl|sed|txt)", "test"], files)) 22print("#4", inc_all(["(pl|sed|txt)", "(test|usb)", "~"], files)) 23
- #1: "pl" "test"を全て含むファイル名を列挙
- #2: "pl" "test"のいずれかを含むファイル名を列挙
- #3: "pl" "sed "txt" のいずれかと"test"を全て含むファイル名を列挙
- #4: "pl" "sed "txt" のいずれかと"test" "usb"のいずれかと"~"を全て含むファイル名を列挙
実行するとこんな感じ
['test.py', 'test.pl', 'test.py~', 'test.pl~', 'out.aa', 'test.sh~', 'out.af', 'test.c~', 'test.r', 'test.csv~', 'my_r.r', 'test.sed', 'test.sh', 'out.ae', 'test.txt', 'test.c', 'out.ac', 'daytest.r', 'remount_usb.txt', 'remount_usb.sh', 'test.zip', 'test.r~', 'remount_usb.pl~', 'test.csv', 'out.ad', 'test.sed~', 'remount_usb.pl', 'out.ab'] #1 ['test.pl', 'test.pl~'] #2 ['test.py', 'test.pl', 'test.py~', 'test.pl~', 'test.sh~', 'test.c~', 'test.r', 'test.csv~', 'test.sed', 'test.sh', 'test.txt', 'test.c', 'daytest.r', 'test.zip', 'test.r~', 'remount_usb.pl~', 'test.csv', 'test.sed~', 'remount_usb.pl'] #3 ['test.pl', 'test.pl~', 'test.sed', 'test.txt', 'test.sed~'] #4 ['test.pl~', 'remount_usb.pl~', 'test.sed~']
(a|b)を許容するならinc_oneはわざわざ用意する必要ないという説もありますが…
投稿2017/12/15 08:54
総合スコア13671
0
自分しか使わないならeval
で絞り込みコードを直指定するという荒業も。
スクリプト書き換えた方が早(略
Python
1pathname = input('pathname: ') # * など 2recursive = input('recursive:') == 'True' # True (or False) 3function = input('function: ') # path.find('subdir1') >= 0 and ( basename.endswith('.txt') or basename.endswith('.jpg')) など 4 5is_target = eval('lambda path,basename:' + function) 6 7import glob 8import os 9target_files = [] 10for path in glob.iglob(pathname,recursive=recursive): 11 if is_target(path, os.path.basename(path)): 12 target_files.append(path) 13 14print(target_files)
実行例
Plain
1>python hoge.py 2pathname: ./dir/** 3recursive:True 4function: True 5['./dir\', './dir\subdir1', './dir\subdir1\test.dat', './dir\subdir1\test.jpg', './dir\subdir1\test.txt', './dir\subdir2', './dir\subdir2\test.dat', './dir\subdir2\tes 6t.jpg', './dir\subdir2\test.txt'] 7 8>python hoge.py 9pathname: ./dir/** 10recursive:True 11function: path.find('subdir1') >= 0 and ( basename.endswith('.txt') or basename.endswith('.jpg')) 12['./dir\subdir1\test.jpg', './dir\subdir1\test.txt']
投稿2017/12/15 01:32
総合スコア38262
0
python
1from functools import partial 2from glob import iglob 3from operator import contains 4 5 6def iglob_ex(pathname, *keywords, op=any, **kwargs): 7 for f in iglob(pathname, **kwargs): 8 if op(map(partial(contains, f), keywords)): 9 yield f 10 11 12print('# any -> OR') 13for f in iglob_ex('*.py', 'wa', 'r', op=any): 14 print(f) 15 16 17print('# all -> AND') 18for f in iglob_ex('*.py', 'x', 'te', op=all): 19 print(f)
投稿2017/12/15 01:18
総合スコア6142
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/12/14 16:20
2017/12/14 16:30
2017/12/15 14:25