2017-07-19 37 views
1

我正在製作一個腳本,通過檢查文件中的已知關鍵字將視頻文件分類到文件夾中。隨着關鍵字數量的增長失控,腳本變得非常慢,需要幾秒鐘處理每個文件。根據關鍵字排序文件,需要更多的數據庫-y解決方案

@echo off  
cd /d d:\videos\shorts 
if /i not "%cd%"=="d:\videos\shorts" echo invalid shorts dir. && exit /b 

:: auto detect folder name via anchor file 
for /r %%i in (*spirit*science*chakras*) do set conspiracies=%%~dpi 
if not exist "%conspiracies%" echo conscpiracies dir missing. && pause && exit /b 
for /r %%i in (*modeselektor*evil*) do set musicvideos=%%~dpi 
if not exist "%musicvideos%" echo musicvideos dir missing. && pause && exit /b 

for %%s in (*) do set "file=%%~nxs" & set "full=%%s" & call :count 
for %%v in (*) do echo can't sort "%%~nv" 
exit /b 

:count 
set oldfile="%file%" 
set newfile=%oldfile:&=and% 
if not %oldfile%==%newfile% ren "%full%" %newfile% 

set count=0 
set words= & rem 
echo "%~n1" | findstr /i /c:"music" >nul && set words=%words%, music&& set /a count+=1 
echo "%~n1" | findstr /i /c:"official video" >nul && set words=%words%, official video&& set /a count+=2 
set words=%words:has, =has % 
set words=%words: , =% 
if not %count%==0 echo "%file%" has "%words%" %count%p for music videos 
set musicvideoscount=%count% 

set count=0 
set words= & rem 
echo "%~n1" | findstr /i /c:"misinform" >nul && set words=%words%, misinform&& set /a count+=1 
echo "%~n1" | findstr /i /c:"antikythera" >nul && set words=%words%, antikythera&& set /a count+=2 
set words=%words:has, =has % 
set words=%words: , =% 
if not %count%==0 echo "%file%" has "%words%" %count%p for conspiracies 
set conspiraciescount=%count% 

set wanted=3 
set winner=none 

:loop 
:: count points and set winner (in case of tie lowest in this list wins, sort accordingly) 
if %conspiraciescount%==%wanted% set winner=%conspiracies% 
if %musicvideoscount%==%wanted% set winner=%musicvideos% 
set /a wanted+=1 
if not %wanted%==15 goto loop 

if not "%winner%"=="none" move "%full%" "%winner%" >nul && echo "%winner%%file%" && echo. 

注意每個關鍵字的「權重值」。它會計算每個類別的總點數,找到最大值並將文件移至指定給該類別的文件夾。它還顯示它找到的單詞,最後列出它找到的無法分類的文件,以便我可以添加關鍵字或調整權重值。

我已將本示例中的文件夾和關鍵字數量減至最少。完整的腳本有六個文件夾和64k大小的所有關鍵字(和增長)。

+0

如果你想在PowerShell中使用它,你首先需要自己做一些基本的代碼,如果你有問題,請回答*關於什麼不工作的具體問題。從我所看到的情況來看,現有批處理代碼的主要問題在於性能,對嗎? – gravity

+0

我明白了。沒錯,性能。我懷疑這是做錯事情的主要例子。我遇到的唯一的實際問題是特殊字符。 – bricktop

回答

3
@ECHO OFF 
SETLOCAL 
SET "sourcedir=U:\sourcedir" 
SET "tempfile=%temp%\somename" 
SET "categories=music conspiracies" 
REM SET "categories=conspiracies music" 
(
FOR /f "tokens=1,2,*delims=," %%s IN (q45196316.txt) DO (
FOR /f "delims=" %%a IN (
    'dir /b /a-d "%sourcedir%\*%%u*" 2^>nul' 
) DO (
    ECHO %%a^|%%s^|%%t 
) 
) 
)>"%tempfile%" 

SET "lastname=" 

FOR /f "tokens=1,2,*delims=|" %%a IN ('sort "%tempfile%"') DO (
CALL :resolve %%b %%c "%%a" 
) 
:: and the last entry... 
CALL :resolve dummy 0 

GOTO :EOF 

:resolve 
IF "%~3" equ "%lastname%" GOTO accum 
:: report and reset accumulators 
IF NOT DEFINED lastname GOTO RESET 
SET "winner=" 
SET /a maxfound=0 
FOR %%v IN (%categories%) DO (
FOR /f "tokens=1,2delims=$=" %%w IN ('set $%%v') DO CALL :compare %%w %%x 
) 
IF DEFINED winner ECHO %winner% %lastname:&=and% 
:RESET 
FOR %%v IN (%categories%) DO SET /a $%%v=0 
SET "lastname=%~3" 
:accum 
SET /a $%1+=%2 

GOTO :eof 

:compare 
IF %2 lss %maxfound% GOTO :EOF 
IF %2 gtr %maxfound% GOTO setwinner 
:: equal scores use categories to determine 
IF DEFINED winner GOTO :eof 
:Setwinner 
SET "winner=%1" 
SET maxfound=%2 
GOTO :eof 

您需要更改sourcedir的設置以適合您的情況。

我使用了一個名爲q45196316.txt的文件,其中包含此類別數據用於我的測試。

music,6,music 
music,8,Official video 
conspiracies,3,misinform 
conspiracies,6,antikythera 
missing,0,not appearing in this directory 

我相信你的問題是反覆執行findstr是耗時的。

該方法使用包含category,weight,mask行的數據文件。所述categories變量包含優先順序排列的類別的列表(用於當分數等於)

讀取數據文件,以%%s,權重分配類別%%t和掩碼到%%u,然後用做一個目錄掃描面具。這將echo對於找到的每個名稱匹配的格式爲name|category|weight的臨時文件的一行。第一次掃描後,dir似乎非常快。

由此產生的臨時文件將爲每個文件名+類別加上權重,因此如果文件名適合多個類別,則會創建多個條目。

然後,我們掃描該文件的排序版本並解析分數。

首先,如果文件名更改,我們可以報告最後的文件名。這通過比較變量$categoryname中的值來完成。由於這些按照%categories%的順序掃描,因此如果分數相等,則選擇列表中的第一個分類。然後重新設置分數並將lastname初始化爲新的文件名。

然後,我們積累的比分進入$categoryname

所以 - 我相信會更快一點。


修訂

@ECHO OFF 
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "sourcedir=U:\sourcedir" 
SET "tempfile=%temp%\somename" 
SET "categories="rock music" music conspiracies" 
REM SET "categories=conspiracies music" 
:: set up sorting categories 
SET "sortingcategories=" 
FOR %%a IN (%categories%) DO SET "sortingcategories=!sortingcategories!,%%~a" 
SET "sortingcategories=%sortingcategories: =_%" 
:: Create "tempfile" containing lines of name|sortingcategory|weight 
(
FOR /f "tokens=1,2,*delims=," %%s IN (q45196316.txt) DO (
SET "sortingcategory=%%s" 
SET "sortingcategory=!sortingcategory: =_!" 
FOR /f "delims=" %%a IN (
    'dir /b /a-d "%sourcedir%\*%%u*" 2^>nul' 
) DO (
    ECHO %%a^|!sortingcategory!^|%%t^|%%s^|%%u 
) 
) 
)>"%tempfile%" 

SET "lastname=" 

SORT "%tempfile%">"%tempfile%.s" 

FOR /f "usebackqtokens=1,2,3delims=|" %%a IN ("%tempfile%.s") DO (

CALL :resolve %%b %%c "%%a" 
) 
:: and the last entry... 
CALL :resolve dummy 0 

GOTO :EOF 
:: resolve by totalling weights (%2) in sortingcategories (%1) 
:: for each name (%3) 
:resolve 
IF "%~3" equ "%lastname%" GOTO accum 
:: report and reset accumulators 
IF NOT DEFINED lastname GOTO RESET 
SET "winner=none" 
SET /a maxfound=0 
FOR %%v IN (%sortingcategories%) DO (
FOR /f "tokens=1,2delims=$=" %%w IN ('set $%%v') DO IF %%x gtr !maxfound! (SET "winner=%%v"&SET /a maxfound=%%x) 
) 
ECHO %winner:_= % %lastname:&=and% 
:RESET 
FOR %%v IN (%sortingcategories%) DO SET /a $%%v=0 
SET "lastname=%~3" 
:accum 
SET /a $%1+=%2 

GOTO :eof 

我增加了一些顯著的意見。

您現在可以在類別名稱中包含空格 - 您需要在set catagories...語句中引用該名稱(用於報告目的)。

sortingcategories是自動派生的 - 它僅用於排序,並且只是名稱中任何空格替換爲下劃線的類別。

在創建臨時文件時,該類別被處理爲包含下劃線(sortingcategory),並且解析最終放置位置時,將刪除下劃線返回類別名稱。

現在應該適當地處理負面權重。

+0

我正在花時間瞭解代碼。它運作良好,但我希望它有可能在其中有空格的類別名稱。我嘗試使用''音樂視頻''而不是'音樂',但它不起作用(可能很明顯)。我不明白代碼的好處,在這一點上做了大量的編輯... – bricktop

+0

我注意到我可以在數據庫文件中使用'?'作爲通配符。非常好!我希望我也可以使用負面的體重值,這對排序困難的東西會有幫助。現在使用負值將文件​​放入第一個類別。 – bricktop

+0

噢,我的,看起來像一個接近完整的重寫。我非常感謝你,所以謝謝你!這就是說,我可以麻煩你最後一件事;可以爲找到的關鍵字添加回顯?我不確定我自己可以做到這一點。我必須承認,我更難以解決這個問題。 – bricktop

相關問題