batch file随机删除文本文件的一半行?

我需要一种方法来使用批处理来查看文本文件的每一行,并删除该文本文件中的一半行,并随机select要删除的行。

这是模拟D&D游戏中的比赛。 我所需要的只是一个方法来榨取每场比赛的冠军。 我可以很容易地创build一个batch file,复制文本文件,并为每一轮重命名,但是这是减less了一半,我不擅长。

编辑:我想要一个batch file来做到这一点,因为它会花费很多时间在表上手动。 此外,游戏中的游戏非常古老,angular色扮演重点突出,所以在锦标赛中有一个NPC名单的实际列表,个人电脑会想知道他们的朋友们在比赛中的performance。

此方法保留原始行的顺序。

@echo off setlocal EnableDelayedExpansion rem Generate an array of line numbers with all file lines for /F "delims=:" %%a in ('findstr /N "^" input.txt') do ( set "n[%%a]=%%a" set "lines=%%a" ) rem Delete half the numbers in the array in random order set /A halfLines=lines/2 for /L %%n in (%lines%,-1,%halfLines%) do ( set /A rnd=!random!*%%n/32768+1 set /A n[!rnd!]=n[%%n] set "n[%%n]=" ) rem Reorder the resulting elements for /F "tokens=2,3 delims=[]=" %%i in ('set n[') do ( set "l[%%j]=1" set "n[%%i]=" ) rem Copy such lines (for /F "tokens=1* delims=:" %%a in ('findstr /N "^" input.txt') do ( if defined l[%%a] ( echo(%%b set "l[%%a]=" ) )) > output.txt 

问题中指定的设计是有缺陷的。 你不能随意删除一半,因为那么对于任何给定的游戏,你最终可能会获得2个获胜者,或者没有获胜者。 输入文件必须有一个结构,指定哪些参赛者互相比赛,然后从每场比赛中随机选出一个获胜者。

下面的解决方案假定每行代表一个玩家,并且对于每一轮,第1行玩第2行,第3行玩第4行等等。行数必须总是2> = 2的幂(2,4,8, 16,32,64,…)

 @echo off setlocal enableDelayedExpansion set "file=tournament.txt" for /f %%C in ('find /c /v "" ^<"%file%"') do ( for /l %%N in (1 2 %%C) do ( set /p "p1=" set /p "p2=" set /a "1/(!random!%%2)" 2>nul&&echo !p1!||echo !p2! ) ) <"%file%" >"%file%.new" move /y "%file%.new" "%file%" >nul 

外循环计算行数。 内部循环从1到奇数进行计数,所以它会精确地迭代(行数除以2)次。 内部循环将输入重定向到源文件,输出重定向到临时文件。

每个内循环迭代表示锦标赛中的一场比赛。 SET / P用于将玩家名称加载到变量中。 然后1除以随机数模2,这将导致50%的时间除以0的错误。 错误消息被重定向到nul,然后使用条件运算符将一个或另一个玩家打印到输出文件。

完成循环后,临时文件将被移动以替换原始文件。

这是一个本地Windows批处理脚本,使用Jscript来随机化文本文件的行并打印一半。

该文件的大小限于Jscript能够请求的RAM。

 @if (@X)==(@Y) @end /* harmless hybrid line that begins a JScript comment :batch file portion @echo off if "%~1"=="" ( echo(Purpose: Randomises a text file - prints every 2nd random line echo( echo(Syntax: "%~0" "inputfile.txt" ^> "outputfile.txt" echo( pause goto :EOF ) :: Randomises a file :: :: Reads the lines of file %1 into a jscript sparse array :: with a random number and space before each line. :: The array is sorted using the random numbers, :: and the randomised lines are printed - prints every 2nd random line @echo off cscript //E:JScript //nologo "%~f0" %* :pause exit /b ************ JScript portion ***********/ e=0; var array = new Array(); fso = new ActiveXObject("Scripting.FileSystemObject"); input=fso.OpenTextFile((WScript.Arguments(0)),1); while (!input.AtEndOfStream) { array[e]=Math.random()+" "+input.ReadLine(); e++; } input.close(); array.sort(); var re = new RegExp(".*? (.*)"); c=0; while (c<e) { var arr = re.exec(array[c]) if (c % 2) WScript.StdOut.Writeline(RegExp.$1); c++; } 
 @echo off setlocal enableextensions disabledelayedexpansion set "inputFile=list.txt" set "outputFile=remaining.txt" set "odd=1" >"%outputFile%" ( for /f "tokens=1,* delims=¬" %%a in (' "cmd /q /v /e /c" for /f "usebackq delims=" %%l in ("%inputFile%"^) do ( set /a 100000000+%random%*^!random^!^&echo(¬%%l ^) "" ^| sort /+3 ') do if not defined odd ( set "odd=1" ) else ( echo %%b set "odd=" ) ) type "%outputFile%" 

这将采取输入文件,为每一行回声与其随机前缀的内容,排序此列表使用随机数作为关键,从这个列表只回声奇数行输出文件。

编辑我已经看到了Aacini的答案 ,是的,它有输出的顺序比输入有用。 如果是这样的话,只需要有另一个版本

 @echo off setlocal enableextensions disabledelayedexpansion set "inputFile=list.txt" set "outputFile=remaining.txt" setlocal enabledelayedexpansion rem Retrieve and calculate line limits to process for /f %%a in ('^<"!inputFile!" find /c /v ""') do set /a "nLines=%%a", "nLimit=%%a/2" rem Prepare an array with shuffled line numbers for /l %%a in (1 1 %nlines%) do ( set /a "sel=!random! %% %%a + 1" if !sel!==%%a ( set "r[%%a]=%%a" ) else ( for %%s in (!sel!) do set /a "r[%%a]=!r[%%s]!", "r[%%s]=%%a" ) ) rem Read input file and output selected lines <"!inputFile!" >"!outputFile!" ( for /l %%a in (1 1 %nLines%) do ( set /p "line=" || set "line=" if !r[%%a]! leq %nLimit% echo(!line! ) ) type "!outputFile!" 

包括PowerShell解决方案的完整性。

 $lines = Get-Content input.txt $lines | foreach { $i=0 } { [PSCustomObject]@{index=$i;line=$_} $i++ } | Get-Random -count ($lines.length / 2) | sort index | select -Expand line | Set-Content output.txt 

这读取输入文件,并建立一个自定义对象的数组,将文本与其行号关联。 脚本使用Get-Random来选择一半的行。 Get-Random不保存顺序,所以脚本会在原始行号上进行排序。 然后按顺序提取原始行并将其写出。

上面的脚本需要PSCustomObject的PowerShell 3.0。 3.0版预装在Windows 7及更高版本上。 如果您需要在Vista上运行,则可以使用PSObject来代替,如本答案或此博客文章中所示 。

请注意,如果行顺序不重要,那么这个脚本就变得简单了。

 $lines = Get-Content input.txt $lines | Get-Random -count ($lines.length / 2) | Set-Content output.txt 

要从批处理文件或CMD提示符运行PowerShell脚本,请使用以下命令。

 powershell.exe -ex bypass -file yourscript.ps1 

或者如果你的脚本完全适合一行,不需要创建一个单独的ps1

 powershell.exe -c "$l = gc input.txt; $l | Get-Random -c ($l.length / 2) | sc output.txt"