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

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

ただいまの
回答率

89.89%

バッチファイルにD&Dしたファイルをpythonで読み込み、ファイル名ごとにフォルダ分けがしたい

解決済

回答 2

投稿

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

SILASSETH

score 3

前提・実現したいこと

バッチファイルにD&Dしたファイルをpythonで読み込み、ファイル名ごとにフォルダ分けがしたい

具体的には

(xxx) [yyy (zzzz)]123456.zip を D&D した際に、指定したフォルダ(D:\sagyo\aaa\yyy(zzzz)\)に ファイル名の[]内のフォルダ名の下に移動する(フォルダがなければ作成する)

C:\(xxx) [yyy (zzzz)]123456.zip をバッチファイルにD&D した際に

D:\sagyo\aaa\yyy(zzzz)\(xxx) [yyy (zzzz)]123456.zip

のように移動していてほしいということです。

また、ファイル名に2つの[]が現れた際(入れ子でない)は、最初の[]を採用するようにもしておきたいです。(re.searchは最初の検索結果を採用すると書いてあったので採用しています。)
例:(xxx) [yyy (zzzz)]123456[aaa].zip なら[yyy (zzzz)]を採用。

見よう見まねでコードを書いてみたのですが、どうして動かないのか分からないので、ご教授願いたいです。
正規表現は試行錯誤すれば書ける(かつ私の環境での汎用性が高くなる)ので、できれば正規表現は使いたいです。

よろしくお願い致します。

発生している問題・エラーメッセージ

D:\sagyo>python zip.py "D:\sagyo\(xxx) [yyy (zzzz)]123456.zip"
zip.py -> D:\sagyo\aaa\None\None
Traceback (most recent call last):
  File "C:\Users\---\AppData\Local\Programs\Python\Python37\lib\pathlib.py", line 1258, in mkdir
    self._accessor.mkdir(self, mode)
OSError: [WinError 123] ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。: "D:\\sagyo\\aaa\\<re.Match object; span=(15, 27), match='[yyy (zzzz)]'>"

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "zip.py", line 14, in <module>
  File "C:\Users\---\AppData\Local\Programs\Python\Python37\lib\pathlib.py", line 1267, in mkdir
    if not exist_ok or not self.is_dir():
  File "C:\Users\---\AppData\Local\Programs\Python\Python37\lib\pathlib.py", line 1358, in is_dir
    return S_ISDIR(self.stat().st_mode)
  File "C:\Users\---\AppData\Local\Programs\Python\Python37\lib\pathlib.py", line 1168, in stat
    return self._accessor.stat(self)
OSError: [WinError 123] ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。: "D:\\sagyo\\aaa\\<re.Match object; span=(15, 27), match='[yyy (zzzz)]'>"

該当のソースコード

python zip.py %1
timeout 100
import shutil
from pathlib import Path
import sys
import re

output_dir = Path("D:/sagyo/aaa")  # 出力ディレクトリ

for path in sys.argv:
        name = re.search(r'\[.*\]' , path)
        name = str(name)

        # サブディレクトリを作成する。
        output_subdir = output_dir / name
        output_subdir.mkdir(parents=True, exist_ok=True)

        # 移動先のファイルパス
        output_path = output_subdir / name
        print(f"{path} -> {output_path}")

        # ファイルを移動する。
        shutil.move(path, output_path)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

テストはしてませんが、output_subdir と output_path は合っていると思います。

import shutil
from pathlib import Path
import sys
import re

output_dir = Path("D:/sagyo/aaa")  # 出力ディレクトリ

for arg in sys.argv[1:]:
    result = re.search('(\[.*\])' , arg)
    sub_folder = result.group(0)
    path = Path(arg)

    # サブディレクトリを作成する。
    output_subdir = output_dir / sub_folder
    output_subdir.mkdir(parents=True, exist_ok=True)

    # 移動先のファイルパス
    output_path = output_subdir / path.name
    print(f"{path} -> {output_path}")

    # ファイルを移動する。
    shutil.move(path, output_path)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/15 15:47

    無事ファイル移動が可能になりました。ありがとうございました。

    補足ですが、batファイルは
    for %%a in (%*) do (
    %~dp0\zip.py %%a
    echo %%a
    と、書き直した上で動かしました。

    キャンセル

0

必要最小限のコードにして、ちょっとずつ期待した動作になるのかを確認しながら
実装を進めることをお勧めします。

ポイントは所定の文字列がうまく抽出されるかではないでしょうか。

そもそも、re.searchの戻り値をstrでは期待通りに動作しないと思います。

import re

str = "(xxx) [yyy (zzzz)]123456[aaa].zip"

name = re.search(r'\[.*\]' , str)
print(name.group())


上記で確認すると、結果は以下のようになります。
[yyy (zzzz)]123456[aaa]

期待通りの結果になるためには、「python re search」などでググってみましょう。
https://note.nkmk.me/python-re-match-search-findall-etc/
*?で非貪欲マッチができるとあります。

そこで、search部分を以下のように修正します。

import re

str = "(xxx) [yyy (zzzz)]123456[aaa].zip"

name = re.search(r'\[.*?\]' , str)
print(name.group())


以下のような結果となりました。
[yyy (zzzz)]

そこで、以下のようにすると、期待した文字列が取得できるようになります。

name = name.group()

さらにそこからパスを生成するためには、以下のようにすることをお勧めします。

import os

name = name.group()
path = os.path.join(output_dir, name)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/07 20:37

    そのサイトは私も拝見したのですが
    「マッチする部分が複数ある場合は、最初のマッチ部分のみが返される。」と書いてあったので、最初の[]がヒットするものだと勘違いしてしまいました。ご指摘ありがとうございます。

    確かに最初から文字列で書けば認識されるのですが、batファイルからpathを受けて動かすと

    Traceback (most recent call last):
    File "zip.py", line 12, in <module>
    name = name.group()
    AttributeError: 'NoneType' object has no attribute 'group'

    で止まります……

    キャンセル

  • 2020/01/08 10:33

    re.search の結果がNoneになっています。その部分の修正が間違えているのではないでしょうか。

    キャンセル

  • 2020/01/09 02:50

    output_dir = Path("D:/sagyo/aaa") # 出力ディレクトリ

    for path in sys.argv:
    name = re.search(r'\[.*?\]' , path)
    name = name.group()
    path = os.path.join(output_dir, name)

    という形なのですが、noneになってしまうのは何故なのでしょうか……。

    キャンセル

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

  • ただいまの回答率 89.89%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる