批处理文件随机删除文本文件的一半行?

时间:2015-09-05 20:03:01

标签: windows batch-file

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

这是为了模拟D& D游戏中的锦标赛。我所需要的只是一种方法来扼杀每轮比赛的获胜者。我可以轻松制作一个复制文本文件的批处理文件,并为每一轮重命名,但是减少了一半,我不擅长。

编辑:我想要一个批处理文件来执行此操作,因为它需要花费很多时间在桌面上手动完成。此外,该游戏非常古老且角色扮演重点突出,因此游戏中有一个NPC角色的实际列表,PC将想知道他们的朋友在比赛中的表现。

6 个答案:

答案 0 :(得分:1)

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

@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

答案 1 :(得分:1)

问题中指定的设计存在缺陷。你不能随意删除一半的线,因为对于任何给定的游戏,你可能最终得到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,然后使用条件运算符将一个或另一个播放器打印到输出文件。

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

答案 2 :(得分:0)

@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's answer,是的,输出的输出顺序与输入顺序相同。如果是这种情况,只需要另一个版本

@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!"

答案 3 :(得分:0)

这是一个本机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++;
  }

答案 4 :(得分:0)

包含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不保留顺序,因此脚本会对原始行号进行排序。然后它按顺序提取原始行并将其写出来。

以上此脚本需要PowerShell 3.0才能使用PSCustomObject。版本3.0预装在Windows 7及更高版本上。如果您需要在Vista上运行,则可以改为使用PSObject,如this answerthis blog post所示。

请注意,如果换行符不重要,那么此脚本会变得更加简单。

$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"

答案 5 :(得分:0)

执行此操作的一种方法是为每个角色创建简单文件。然后使用随机脚本执行以下操作:

set/a number=%random% * (number of people there are) / 32768 + 1
set status=dead
call person%number%.bat   (Each file should contain a set status=live script)
if %status% == live (
set/a peopletokill=%peopletokill%-1
del person%number%.bat
)
if %peopletokill% == 0 (
exit
)

这样的事情可行。