質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Python 3.x

    6920questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 正規表現

    813questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • zip

    60questions

    ZIPとは、複数のファイルをひとつにまとめて圧縮したり、圧縮したファイルを展開することができるアーカイブフォーマットです。 1998年以降のWindowsOS各バージョンで、標準の圧縮フォルダとして採用されています。 MacOSでも、X v10.3以降に他の圧縮ソフトとまとめてZIP機能を採用しています。

Pythonで、正規表現を使って特定条件だけZIPファイルに追加したい

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 417

ky_46

score 77

Pythonで、正規表現を使って特定条件だけZIPファイルに追加したい

 前提・実現したいこと

pythonで指定ディレクトリの中からファイルを選んでZIPファイルに格納したい

 発生している問題

image_1.jpg
image_2.jpg
image_3.jpg'
image-cv01.jpg
image-cv21.jpg
image-cv31.jpg
image.jpg
image_100.jpg

例として、上記のようなファイルリストがあったとします。
数字の部分は決まった形式なので変わることはありませんが、数字の最大値は状況により変わります。

これから

image_3.jpg'
image-cv01.jpg
image-cv21.jpg
image-cv31.jpg

を格納したsyoko.zipを作成するのが希望動作です。

つまり、image_[数字一桁]なら最大値のファイルのみ、image-cv[数字二桁]なら全ファイルを追加。imageだけで何もないファイルや、_[数字三桁]などは圧縮ファイルへ追加しないという動作になります。

 該当のソースコード

wodir = '上記のファイルが格納されたフォルダを指定'
files = []

#直下のファイル一覧取得
    for x in os.listdir(wodir):
        if os.path.isfile(wodir + x):
            files.append(x)


    compFile01 = zipfile.ZipFile(syoko.zip', 'w', zipfile.ZIP_DEFLATED)
    for y in files:
        pattern = 'image' + r"_[0-9]{1}\.jpg"
        matchOB = re.match(pattern, y)
        if matchOB:  # ファイル名がパターンとマッチしたら追加
            compFile01.write(y)

        pattern = 'image' + r"-cv[0-9]{2}\.jpg"
        matchOB = re.match(pattern, y)
        if matchOB:  # ファイル名がパターンとマッチしたら追加
            compFile02.write(y)

    compFile01.close()

結果、出来上がったsyoko.zipは、
image_1.jpg
image_2.jpg
image_3.jpg'
image-cv01.jpg
image-cv21.jpg
image-cv31.jpg

のようにimage_[数字1文字]のファイルを全部ひっかけてしまいます。

いろいろGoogleなどで調べてみたのですが、数字一桁の最も大きいものだけを抽出する方法が見つけられません。

あるいは、pythonでzipから指定したファイルを削除できれば、とも思ったのですが、上記コードで最大値を確保する方法や、圧縮ファイルからファイルを除去する方法も見つけられずにおります。

よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

結局のところ対処すべきは2パターンのみ。
正規表現よりもglobを使ったほうがシンプルな気がします。

import glob
import zipfile

targets = []

for f in sorted(glob.glob("./image_?.jpg")):
  target=f
targets.append(target)

for f in glob.glob("./image_cv??.jpg"):
  targets.append(f)

compFile01 = zipfile.ZipFile('syoko.zip', 'w')
for y in targets:
  compFile01.write(y)
compFile01.close()

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 15:20

    glob というのはGoogleで得られなかったので、知識として助かりました。今回の質問範囲と違うので情報に入れなかったのですが、実はこの後、zipに格納しなかったimage.jpg とimage_100.jpgを指定のフォルダに移動する作業があるので、それを組み込みするとき使えそうです。ありがとうございます。

    キャンセル

+2

pattern1 = re.compile(r'^image_[0-9]{1}\.jpg$')
pattern2 = re.compile(r'^image-cv[0-9]{2}\.jpg$')
comp_files = sorted([file for file in files if pattern1.match(file)])[-1:] + [file for file in files if pattern2.match(file)]
print(comp_files)
#['image_3.jpg', 'image-cv01.jpg', 'image-cv21.jpg', 'image-cv31.jpg']

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 15:15

    ご回答ありがとうございます。今回はhayataka2049様の方法で解決といたしました。感謝です。

    キャンセル

checkベストアンサー

+1

  • 入れるべきファイル名は先に走査して決め、実際の処理は後でまとめて行う
  • image_[数字1文字]はとりあえずぜんぶ見てからmaxを取る

という方針で行きましょう。

filename_lst1 = []
filename_lst2 = []
for y in files:
    pattern = 'image' + r"_[0-9]{1}\.jpg"
    matchOB = re.match(pattern, y)
    if matchOB:  # ファイル名がパターンとマッチしたら追加
        filename_lst1.append(y)

    pattern = 'image' + r"-cv[0-9]{2}\.jpg"
    matchOB = re.match(pattern, y)
    if matchOB:  # ファイル名がパターンとマッチしたら追加
        filename_lst2.append(y)

max_filename = max(filename_lst1, key=lambda x:int(x[6]))

compFile01 = zipfile.ZipFile('syoko.zip', 'w', zipfile.ZIP_DEFLATED)
for y in filename_lst2 + [max_filename]:
    compFile01.write(y)
compFile01.close()

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 15:11

    ご回答ありがとうございます。

    > max_filename = max(filename_lst1, key=lambda x:int(x[6]))

    この部分は、「filename_lst1を、文字列を0から勘定して6番目を数字にしてソートする」という理解であっていますでしょうか?

    試してみたところ、image_1の数字の部分を見事にソートして、最大値をひっかけました。

    大変助かりました。ありがとうございます。

    キャンセル

  • 2018/05/05 18:01

    ソートするというか、そのまま最大値ですね

    キャンセル

+1

ファイル一覧をソートして、
image_[数字一桁]のパターンのファイルは。その最後のものだけを対象にするようにしました。
さらに subfolder にも対応させてみました。

a.py

import os
import re
import zipfile

def file_filter(files):
    target_1 = None
    targets = []
    for file in sorted(files):
        pattern = r"image\_[0-9]\.jpg"
        if re.match(pattern, file):
            target_1 = file
            next
        pattern = r"image\-cv[0-9]{2}\.jpg"
        if re.match(pattern, file):
            targets.append(file)

    if target_1:
        targets.append(target_1)
    return targets


src_dir = "data"
zip_path = "syoko.zip"
with zipfile.ZipFile(zip_path, 'w') as zip_file:
    for folder, subfolders, files in os.walk(src_dir):
        target_files = file_filter(files)

        if len(target_files) > 0:
            zip_file.write(folder)
            for file in target_files:
                zip_file.write(os.path.join(folder, file))


実行例

イメージ説明

イメージ説明

参考情報:

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/05 15:25

    ありがとうございます。今回はhayataka2049様の方法で解決といたしました。ただ、サブフォルダ処理は今後、参考にさせていただきます。

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    6920questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • 正規表現

    813questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • zip

    60questions

    ZIPとは、複数のファイルをひとつにまとめて圧縮したり、圧縮したファイルを展開することができるアーカイブフォーマットです。 1998年以降のWindowsOS各バージョンで、標準の圧縮フォルダとして採用されています。 MacOSでも、X v10.3以降に他の圧縮ソフトとまとめてZIP機能を採用しています。