2015-09-05 108 views
-2

我需要一種方法來使用批處理來查看文本文件的每一行,並刪除該文本文件中的一半行,並隨機選擇要刪除的行。批處理文件隨機刪除文本文件的一半行嗎?

這是爲了模擬D & D遊戲中的錦標賽。我需要的只是一個方法來分解每個錦標賽的獲勝者。我可以很容易地創建一個批處理文件來複制文本文件併爲每一輪重新命名它,但是我減少了一半,所以我不善於處理。

編輯:我想要一個批處理文件來做到這一點,因爲它會花費很多時間手動在表上做。此外,該遊戲的遊戲非常古老,角色扮演重點突出,因此在錦標賽中有一系列NPC角色的實際列表,而個人電腦會想知道他們的朋友在比賽中的表現。

+0

爲什麼這需要成爲批處理文件? –

+0

因爲我只能批量編程。 –

+0

發佈您嘗試過的內容,您的代碼和行不通的行。 SO不是一個寫我的軟件網站。 – 2015-09-05 20:11:26

回答

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!" 
+0

您的第一個解決方案有一個潛在的問題,即同一秒內的多次運行都會產生相同的結果,因爲當CMD.EXE啓動時,隨機數生成器將以當前時間(精確到秒)播種。 – dbenham

+0

@dbenham,如果多個實例是從同一個'cmd'實例執行的,那就沒有問題了。如果你看看'set/a 100000000 +%random%* ^!random ^!',你會看到內部(命令行上下文)'cmd'使用父(批)實例中的一個隨機值。如果多個開始(父,批)實例中的每一個都是在一個單獨的'cmd'實例中創建的,那麼當然,您是可行的。 –

+0

我測試了一下,並觀察到你是正確的,但是我無法將自己的頭包裹在算法中!每個人的解決方案似乎對我來說都是不必要的。另外,OP的設計是有缺陷的。你不能在比賽中隨機刪除50%的參賽者。相反,2個預定對手之間的每場比賽必須只有一個贏家。看到[我的答案](http://stackoverflow.com/a/32438269/1012053) – dbenham

0

這是使用Jscript腳本來隨機化他們的文本文件和打印一半的線路本機Windows批處理腳本。

該文件的大小限於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++; 
    } 
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 
+0

我喜歡它,保持線條順序的好主意。 –

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不保留順序,因此腳本會根據原始行號進行排序。然後按順序提取原始行並寫出它們。

以上腳本需要PSCustomObject的PowerShell 3.0。 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" 
+0

對不起,我沒有看到你的「包括PowerShell解決方案的完整性」評論的邏輯。問題只有'windows'和'batch-file'標籤。爲什麼PowerShell解決方案使答案「完整」?我們是否也應該包含Phyton,Ruby,PHP等解決方案以「完整性」?預裝在_all_ Windows版本上的另一種編程語言是JScript(_not_ PowerShell),因此在「批處理文件」標記的問題中包含JScript解決方案以「完整性」似乎比PS更合乎邏輯... – Aacini

+0

「完整性」通過解決用戶問題的程度來判斷案件。根據我的經驗,許多人試圖構建「批處理文件」解決方案,實際上只是想在Windows中使用shell腳本解決方案。 PowerShell是在CMD運行的每個(支持的)操作系統上預先安裝的卓越的Windows腳本語言。它比CMD更好地解決了「我想編寫Windows腳本」的問題,即使用戶不知道要在搜索中輸入什麼內容並放置「批處理」。 –

+0

您的最新評論僅基於_opinions_。我不想在我的意見中發起一個_評論戰,但只保留可驗證的事實。我試圖測試你的程序,但最後兩個版本顯示'Get-Random:無法驗證'InputObject''錯誤消息的參數_79次_(?)。第一個版本運行正常,在Windows 8.1 64位下運行5次後,平均需要2.02秒來處理620行(19 KB)的文件。我的批處理文件解決方案在相同條件下需要0.88秒,所以PowerShell不會比CMD更好地解決(這個)問題(至少不是速度)... – Aacini

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,然後使用條件操作符將一個或另一個播放器打印到輸出文件。

完成循環後,移動臨時文件以替換原始文件。

+0

簡單而優雅。 –

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 
) 

這樣的東西可以工作。

相關問題