Пакетный файл для случайного удаления половины строк текстового файла?
Мне нужен способ использовать пакет для просмотра каждой строки текстового файла и удалить половину строк в этом текстовом файле, выбрав, какие строки удалить случайно.
Это должно имитировать турнир в игре D & D. Все, что мне нужно - это способ победить победителей каждого раунда турнира. Я могу легко создать пакетный файл, который копирует текстовый файл и переименовывает его для каждого раунда, но это уменьшает половину, с которой мне не нравится.
Изменить: мне нужен командный файл, потому что это займет много времени, чтобы сделать это вручную. Также игра очень старая и ролевая игра сосредоточена, поэтому в турнире есть фактический список персонажей NPC, и ПК захотят узнать, как их друзья участвовали в соревнованиях.
Ответы
Ответ 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
Ответ 2
Дизайн, указанный в вопросе, является ошибочным. Вы не можете случайным образом удалить половину строк, потому что тогда для любой заданной игры вы можете получить 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, что приведет к делению на 0 ошибкой в 50% времени. Сообщение об ошибке перенаправляется на nul, а затем условные операторы используются для печати одного или другого игрока в выходной файл.
По завершении цикла временный файл перемещается для замены исходного файла.
Ответ 3
@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!"
Ответ 4
Это родной пакет Windows script, используя Jscript, чтобы рандомизировать строки текстового файла и печатать половину из них.
Размер файла ограничен ОЗУ, которое Jscript может запросить.
@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++;
}
Ответ 5
Включение решения 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
Это считывает входной файл и создает массив настраиваемых объектов, связывающих текст с его номером строки. script использует Get-Random
для выбора половины строк. Get-Random не сохраняет порядок, поэтому script сортирует исходный номер строки. Затем он извлекает исходные строки по порядку и записывает их.
Для этого script выше требуется PowerShell 3.0 для PSCustomObject. Версия 3.0 поставляется предустановленной в Windows 7 и выше. Если вам нужно запустить Vista, вы можете использовать PSObject вместо этого, как показано в этом ответе или this сообщение в блоге.
Обратите внимание, что если порядок строк не имеет значения, то этот script становится намного проще.
$lines = Get-Content input.txt
$lines | Get-Random -count ($lines.length / 2) | Set-Content output.txt
Чтобы запустить PowerShell script из командного файла или приглашения CMD, используйте следующее.
powershell.exe -ex bypass -file yourscript.ps1
Или если ваш script полностью помещается в одну строку, нет необходимости создавать отдельный ps1
powershell.exe -c "$l = gc input.txt; $l | Get-Random -c ($l.length / 2) | sc output.txt"