【问题标题】:Random line of text using batch使用批处理的随机文本行
【发布时间】:2012-10-31 20:14:02
【问题描述】:

如何从文本文件中随机选择一行文本并将其设置在变量中以供使用?

【问题讨论】:

    标签: text random batch-file line


    【解决方案1】:

    就像 StackOverflow 中已经提到的 here 一样,%RANDOM% 扩展为 0 到 32767 之间的随机数。

    您可以使用此机制生成随机行号。但是,要使其成为有效的行号,您必须通过输入文本文件中的行数对其进行规范化。

    这里有一个简单的脚本来说明如何做到这一点:

    @echo off
    setlocal enabledelayedexpansion
    set INPUT_FILE="test.txt"
    
    :: # Count the number of lines in the text file and generate a random number
    set lines=0
    for /f "usebackq" %%a in (%INPUT_FILE%) do set /a lines+=1
    echo %RANDOM% >nul
    set /a randnum=%RANDOM% * !lines! / 32768 + 1
    
    :: # Extract the line from the file
    set lines=0
    for /f "usebackq tokens=*" %%a in (%INPUT_FILE%) do (
        set /a lines+=1
        if !lines!==!randnum! set randline=%%a
    )
    
    echo Line #!randnum! is:
    echo.!randline!
    

    【讨论】:

    • echo %RANDOM% >nul这行有什么用吗?
    • @BaliC 奇怪的是,我需要使用一次%RANDOM% 来“启动”批处理随机数生成器......出于某种奇怪的原因,没有它,我总是得到相同的生成行号。 ..
    【解决方案2】:

    下面的 Batch 程序是 Eitan 的解决方案,稍作修改以运行得更快:

    @echo off
    setlocal EnableDelayedExpansion
    set INPUT_FILE="test.txt"
    
    :: # Count the number of lines in the text file and generate a random number
    for /f "usebackq" %%a in (`find /V /C "" ^< %INPUT_FILE%`) do set lines=%%a
    set /a randnum=%RANDOM% * lines / 32768 + 1, skiplines=randnum-1
    
    :: # Extract the line from the file
    set skip=
    if %skiplines% gtr 0 set skip=skip=%skiplines%
    for /f "usebackq %skip% delims=" %%a in (%INPUT_FILE%) do set "randline=%%a" & goto continue
    :continue
    
    echo Line #%randnum% is:
    echo/!randline!
    

    【讨论】:

    • +1:使用 for 循环内置选项来跳过行。不错。
    • 使用FOR /F "skip=" 功能的想法很棒,获取行数的方法也是如此。但是由于某种原因,当我在我的 Windows 7 HP SP1 机器上测试这个脚本时,生成的数字总是 30000+。这似乎很奇怪,因为当我从命令行测试echo %random% 时,我得到更多 更多不同的数字。无论如何,由于我在测试中使用了一个相当小的文件,randnum 总是最终成为文件中的最后一个行号,因为 %RANDOM% 值很大。
    • 我再次测试它,它再次导致相同的行号,但不同的行号(因为随机数再次在相当接近的范围内生成)。不知道发生了什么。但是,这个想法很明确,应该可以很好地工作,即使仅针对FIND /V /C "",我也毫不犹豫地支持您的答案。
    【解决方案3】:

    这是另一种方法。它从命令行读取文件名并使用FOR /L 循环来获取计算出的行号:

    @ECHO OFF
    FOR /F "" %%I IN ('FIND /C /V "" ^<%1') DO SET /A lines=%%I
    SET /A skip=%RANDOM%%%lines
    <%1 (
      FOR /L %%I IN (1,1,%skip%) DO (
        SET /P line=
      )
      SET line=
      SET /P line=
    )
    ECHO(%line%
    

    FOR /F 循环只是获取文件中的行数(该方法借用自@Aacini's answer)。

    然后一个相当简单的公式计算文件中要跳过的行数。

    接下来,读取文件。 FOR /L 循环仅使用 SET /P 指令消耗指定数量的行。在循环之后,还有一个 SET /P 命令读取最终 ECHO 的行。

    上面的实现只是为了展示基本思想。这并非没有问题,但其中一些问题很容易解决:

    1. 没有测试是否确实提供了参数。如果不存在,脚本将中断。您可以像这样在脚本的开头添加必要的检查:

      IF "%~1"=="" GOTO :EOF
      

      如果没有参数,此命令通过将控件发送到脚本末尾 (GOTO :EOF) 来终止脚本。

    2. 指定的文件可能不存在。同样,您可以在开始时进行测试,在验证是否提供了参数之后,在必要时终止脚本:

      IF NOT EXIST %1 GOTO :EOF
      
    3. 如果文件为空,lines 将为0,使用它的后续表达式将遇到除以零错误。因此,您还需要测试生成的行数(如果行数确实为 0,则阻止脚本进一步运行)。您可以通过在 FOR /F 循环之后添加以下行来做到这一点:

      IF %lines%==0 GOTO :EOF
      
    4. 就像我说的,这个公式有点简单。它不会产生大于 32767 的数字,这是 %RANDOM% 的限制。这对您来说可能已经足够了,但如果不是,您可以使用 two %RANDOM% 这样的调用将范围扩展到 230-1:

      SET /A skip=(%RANDOM%*32768+%RANDOM%)%%lines
      

    所以,这里又是相同的脚本,经过修改以解决上述问题:

    @ECHO OFF
    IF "%~1"=="" GOTO :EOF
    IF NOT EXIST %1 GOTO :EOF
    FOR /F "" %%I IN ('FIND /C /V "" ^<%1') DO SET /A lines=%%I
    IF %lines%==0 GOTO :EOF
    SET /A skip=(%RANDOM%*32768+%RANDOM%)%%lines
    <%1 (
      FOR /L %%I IN (1,1,%skip%) DO (
        SET /P line=
      )
      SET line=
      SET /P line=
    )
    ECHO(%line%
    

    另一个注意事项是,如果您愿意,可以添加消息来解释脚本提前终止的原因。基本上,无论你想在哪里添加消息,你只需要替换单个

    GOTO :EOF
    

    (ECHO <i>your message</i> &amp; GOTO :EOF)

    例如:

    IF NOT EXIST %1 (ECHO Error! File not found & GOTO :EOF)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      相关资源
      最近更新 更多