2017-07-19 24 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

相关问题