从批处理文件中的单词列表中搜索特定单词

时间:2015-06-22 02:05:33

标签: batch-file cmd scripting

我有一个%list%变量,其中包含单词(请参阅代码),我想搜索一个以字母结尾的单词' Y' (忽略区分大小写)并以用户输入的最后一个字母开头。用户输入可以是任何有效的单词。一旦找到该特定单词,我就想将其存储到变量(%myWord%)中。我的目的是稍后在代码中使用%myWord%变量。如果我已经使用%list%中的那个词,那么我想向用户显示一个新单词。我的单词列表以任何字母开头,结尾于' Y'信和字母顺序。 %list%很长。 以下是我的代码。我觉得我迷路了,我无法找到解决这个问题的方法。

@echo off

:START
set /p INPUTWORD=>Enter a word:
SET lastletter=%INPUTWORD:~-1%

set "list=daddy day gladly happily key pay randomly ray say urgency utility yesterday"
For %%L in (%list%) do (
    SET endingY=%%L:~-1%
 For %%X in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
  if findstr /i "%lastletter%" %%X EQU first letter of the words in %list%
   if %%L:~-1% EQU "y"
    if %myWord% is already shown to user then search for a new word.
     and then set myWord==%%L  (new word; unused one)

echo My Word is: %myWord%
pause
goto START

例如:

第一节: 输入一个单词:dog

我的话是:很高兴

第二节: 输入一个单词:yak

我的话是:关键

使用任何类型的功能都完全没问题。只要它搜索正确的单词。 这似乎有可能,但我已经厌倦了思考。我想我可能需要保持新鲜感。

4 个答案:

答案 0 :(得分:1)

您的描述错误。它说:“我想搜索一个以字母”Y“结尾并以用户输入的第一个字母开头的单词”,但代码会查找以 last 字母开头的单词。用户的输入。我的解决方案使用代码规范。

    <body>
        <div class="container">
            <div class="header">
                    <h1>Sokoban</h1>
            </div>

            <div class="nav">
                <div class="nav_wrapper">
                    <ul>
                        <li><a href="home.html">Home</a></li><li>
                        <a href="#">Play</a></li><li>
                        <a href="#">Help</a></li><li>
                        <a href="#">Leaderboards</a>
                            <ul>
                                <li><a href="highScores.html">High Scores</a></li>
                                <li><a href="topLevels.html">Top Levels</a></li>
                                <li><a href="mostCompleted.html">Most completed</a></li>
                            </ul>    
                        </li>
                    </ul>
                </div>
            </div>

            <div class="leftSideBar">
            </div>

            <div class="mainContent">

                <h2>High Scores</h2>

                <div class = "leaderboard">
                        <?php

    // Get a connection for the database
    require_once('../mysqli_connect.php');

    // Create a query for the database
    $query = "SELECT rankNo, username, highScores FROM Users INNER JOIN leaderboardHighScores";

    // Get a response from the database by sending the connection
    // and the query
    $response = @mysqli_query($dbc, $query);

    // If the query executed properly proceed
    if($response){

    echo '<table>
    <tr><td><b>Rank</b></td>
    <td><b>Username</b></td>
    <td><b>High Score</b></td></tr>';


    // mysqli_fetch_array will return a row of data from the query
    // until no further data is available
    while($row = mysqli_fetch_array($response)){

    echo '<tr><td>' .
    $row['rankNo'] . '</td><td>' .
    $row['username'] . '</td><td>' .
    $row['highScores'] . '</td><td>';

    echo '</tr>';
    }

    echo '</table>';

    } else {

    echo "Couldn't issue database query<br />";

    echo mysqli_error($dbc);

    }

    // Close connection to the database
    mysqli_close($dbc);


    ?>  
                </div>
            </div>

            <div class="rightSideBar">
                <h3>Sign in</h3>
                <input type="text" placeholder="Username" class="txtBox" /></br>
                <input type="text" placeholder="Password" class="txtBox" /></br></br>

                <input type="button" value="login" class="btn"/>

                <h2>Sign up<h2>
                <input type="button" value="Create account" class="btn"/>

            </div>
        </div>
    </body>                
</html>

关于这个问题的几点意见:

  • 如果所有单词都以'Y'字母结尾,则无需检查此点(“该单词以'Y'结尾”)。
  • 单词按字母顺序没有任何优点。无论如何,除非要开发更复杂的方法,否则需要检查整个列表以搜索目标词。

答案 1 :(得分:1)

代码注释中包含的说明。

这可能看起来像很多代码,但它实际上非常有效。

由于您的列表中只包含以y结尾的字词,因此无需验证找到的字词是否以y结尾。

此解决方案假设列表中的所有单词至少包含两个字母。

@echo off
setlocal EnableDelayedExpansion

:: The list must start and end with a space, the word order does not matter
set "list= daddy day gladly happily key pay randomly ray say urgency utility yesterday "

:start
echo(

:: Exit if list is empty (nothing but spaces)
if "%list: =%" equ "" (
  echo No more words in list
  exit /b
)

:: Get the users input, exit if none
set "INPUTWORD="
set /p "INPUTWORD=>Enter a word: "
if not defined INPUTWORD exit /b

:: Look for the first word that begins with the last letter of the input
:: and delete everything up through the first letter of the matching word
set "test=!list:* %INPUTWORD:~-1%=!"

:: If the modified list matches the original, then no word was found.
:: Give message and try again
if "%test%" equ "%list%" (
  echo myWord not found
  goto :start
)

:: Get the remainder of the word and rebuild the complete word
for %%W in (%test%) do (
  set "myWord=%INPUTWORD:~-1%%%W"
  goto :break
)
:break

:: Remove the word from the list
set "list=!list: %myWord% = !"

:: Show the result and loop back
echo myWord=%myWord%
goto :start

答案 2 :(得分:1)

此解决方案应该是最有效的方法,因为它将子列表中的原始列表相应地分割为单词的第一个字母。这样,通过if defined subList[%lastLetter%]立即测试是否存在某个单词,并且在更短的变量中提取单词。此外,这种方法很明显,因为代码的大小。

@echo off
setlocal EnableDelayedExpansion

set "list=daddy day gladly happily key pay randomly ray say urgency utility yesterday"

rem Split the list in sub-lists (an array) based on the first letter of the words
for %%w in (%list%) do (
   set "word=%%w"
   for /F %%l in ("!word:~0,1!") do set "subList[%%l]=!subList[%%l]! %%w"
)

ECHO CONTENTS OF THE SUB-LISTS:
SET SUBLIST
ECHO/

:START
set "INPUTWORD="
set /p "INPUTWORD=>Enter a word: "
if not defined INPUTWORD goto :EOF

rem Get last letter of user's input
SET lastLetter=%INPUTWORD:~-1%

rem If a sub-list for that letter exists...
if defined subList[%lastLetter%] (

   rem Extract the first word from such sub-list
   for /F "tokens=1*" %%a in ("!subList[%lastLetter%]!") do (
      set "myWord=%%a"
      set "subList[%lastLetter%]=%%b"
   )

) else (
   set "myWord=Word not found in list"
)

echo My Word is: %myWord%
echo/
goto START

示例会话:

CONTENTS OF THE SUB-LISTS:
subList[d]= daddy day
subList[g]= gladly
subList[h]= happily
subList[k]= key
subList[p]= pay
subList[r]= randomly ray
subList[s]= say
subList[u]= urgency utility
subList[y]= yesterday

>Enter a word: dog
My Word is: gladly

>Enter a word: yak
My Word is: key

>Enter a word: dad
My Word is: daddy

>Enter a word: dad
My Word is: day

>Enter a word: dad
My Word is: Word not found in list

>Enter a word:

有关数组批量的进一步说明,请参阅this post

编辑:我尝试在我的解决方案与dbenham之间实施时间测试,但我无法完成它!

@echo off
setlocal EnableDelayedExpansion

set "list0=daddy day gladly happily key pay randomly ray say urgency utility yesterday"

rem Create the initial list repeating the previous "list0" 100 times (= 1200 words)
rem changing the initial letter by a random one

echo Creating initial list...
set "letter=abcdefghijklmnopqrstuvwxyz"
set "list="
for /L %%t in (1,1,100) do (
   for %%a in (%list0%) do (
      set "word=%%a"
      set /A i=!random! %% 26
      for /F %%i in ("!i!") do set "list=!list! !letter:~%%i,1!!word:~1!"
   )
)


rem ========================
echo Testing Aacini's

rem Start Aacini's code test
for /F "tokens=1-3 delims=:." %%a in ("%time%") do (
   set /A "H=%%a, M=1%%b%%100, S=1%%c%%100, startA=(H*60+M)*60+S"
)

rem Split the list in sub-lists (an array) based on the first letter of the words
for %%w in (%list%) do (
   set "word=%%w"
   for /F %%l in ("!word:~0,1!") do set "subList[%%l]=!subList[%%l]! %%w"
)

rem Get 1000 words selecting a random last letter 

for /L %%? in (1,1,1000) do (

set /A i=!random! %% 26
for /F %%i in ("!i!") do SET "lastLetter=!letter:~%%i,1!"

rem If a sub-list for that letter exists...
if defined subList[!lastLetter!] (

   rem Extract the first word from such sub-list
   for /F %%L in ("!lastLetter!") do for /F "tokens=1*" %%a in ("!subList[%%L]!") do (
      set "myWord=%%a"
      set "subList[%%L]=%%b"
   )

) else (
   set "myWord=Word not found in list"
)

echo %%?- My Word is: !myWord!
REM echo/
REM goto START
)

rem End Aacini's code test
for /F "tokens=1-3 delims=:." %%a in ("%time%") do (
   set /A "H=%%a, M=1%%b%%100, S=1%%c%%100, endA=(H*60+M)*60+S"
)


rem ========================
echo Testing dbenham's


rem Start dbenham's code test

:: The list must start with dot space and end with space dot, the word order does not matter
set "list=. %list% ."

for /F "tokens=1-3 delims=:." %%a in ("%time%") do (
   set /A "H=%%a, M=1%%b%%100, S=1%%c%%100, startD=(H*60+M)*60+S"
)

rem Get 1000 words selecting a random last letter 

for /L %%? in (1,1,1000) do (

set /A i=!random! %% 26
for /F %%i in ("!i!") do SET "LastLetter=!letter:~%%i,1!"

REM :start
REM echo(

Rem Exit if list is empty
if "!list: =!" equ ".." (
  echo No more words in list
  goto endDbenham
)

Rem Iterate value of list after replacing "<space>%LastLetter%" with "<newLine>%LastLetter%".
Rem Skip the first line and take the first token, which will be myWord.
Rem If no substitution, then only one line so DO will not fire.
Rem The empty line below (after the FOR line^) is critical - DO NO REMOVE
set "break="
for /F %%L in ("!LastLetter!") do for /f "usebackq skip=1" %%W in ('!list: %%L^=^

%%L!') do if not defined break (                    

  REM remove myWord from the list
  set "list=!list: %%W = !"

  REM show result and loop back for more (breaks out of loop^)
  echo %%?- myWord = %%W
  REM goto :start
  set "break=Yes"
)

if not defined break (
Rem Only reaches here if myWord not found
echo %%?- myWord not found
REM goto :start
)

)


rem =======================

:endDbenham

rem End dbenham's code test
for /F "tokens=1-3 delims=:." %%a in ("%time%") do (
   set /A "H=%%a, M=1%%b%%100, S=1%%c%%100, endD=(H*60+M)*60+S"
)

set /A elapsedA=endA-startA, elapsedD=endD-startD
echo/
echo Aacini's:  %elapsedA% seconds
echo dbenham's: %elapsedD% seconds

答案 3 :(得分:0)

我相信这是原生批次的终极优化解决方案 - 甚至比Aacini的第二个解决方案更快。

除了将点空间放在列表的前面,并且在末尾放置空格点之外,没有预处理。

它使用行继续(转义行尾)在所需单词之前插入换行符。

@echo off
setlocal EnableDelayedExpansion

:: The list must start with dot space and end with space dot, the word order does not matter
set "list=. daddy day gladly happily key pay randomly ray say urgency utility yesterday ."

:start
echo(

:: Exit if list is empty
if "%list: =%" equ ".." (
  echo No more words in list
  exit /b
)

:: Get the user's input, exit if none
set "INPUTWORD="
set /p "INPUTWORD=>Enter a word: "
if not defined INPUTWORD exit /b

:: Get the last letter of input
set "LastLetter=%INPUTWORD:~-1%"

:: Iterate value of list after replacing "<space>%LastLetter%" with "<newLine>%LastLetter%".
:: Skip the first line and take the first token, which will be myWord.
:: If no substitution, then only one line so DO will not fire.
:: The empty line below (after the FOR line) is critical - DO NO REMOVE
for /f "usebackq skip=1" %%W in ('!list: %LastLetter%^=^

%LastLetter%!') do (                    

  REM remove myWord from the list
  set "list=!list: %%W = !"

  REM show result and loop back for more (breaks out of loop)
  echo myWord = %%W
  goto :start
)

:: Only reaches here if myWord not found
echo myWord not found
goto :start



更新

受Aacini的启发,我对优化方法进行了一些时序测试。我们真的在谈论分裂头发: - )

以下是最终结果:

                       dbenham      Aacini
                     -----------  -----------
Preprocess the list:   2.00 msec  104.00 msec
One input & lookup:    2.91 msec    2.82 msec

唯一重要的区别在于预处理,但就用户体验而言,即使这样也许毫无意义。

以下是我的测试方法:

我删除了所有评论并稍微重新构建了代码,以确保两者都做同样的工作并给出相同的结果。

我编制了一个728个单词的列表(不再以“y”结尾,但这应该不重要)。我还装配了一个551个单词的输入文件,每行一个,包括一个由句点组成的最后一个“单词”,以便它可以识别“未找到单词”分支。

我保存两个脚本的“my word”输出并进行比较以显示它们产生相同的结果。

<强> dbenham.bat

@echo off
setlocal EnableDelayedExpansion

:: Define list
set "base=andy bay cay daddy day easy fly gladly happily inky jay key lay may nay ornery pray quay randomly ray say truancy urgency vacancy way xray yesterday zesty "
for %%L in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set "list=!list! !base: =%%L !"

:: Measure preprocessing time
set t1_0=%time%
set "list=.!list!."
set t1_1=%time%

:: Measure lookup time
set /a cnt=0
set "t2_0=%time%"
:start
echo(
set "INPUTWORD="
set /p "INPUTWORD=>Enter a word: "
if not defined INPUTWORD goto :done
set /a cnt+=1
set "LastLetter=%INPUTWORD:~-1%"
for /f "usebackq skip=1" %%W in ('!list: %LastLetter%^=^

%LastLetter%!') do (                    
  set "list=!list: %%W = !"
  echo My word = %%W
  goto start
)
echo My word not found in list
goto start

:done
set "t2_1=%time%"
call :elapsed t1_0 t1_1 t1
call :elapsed t2_0 t2_1 t2
>&2 echo Preprocessing time for 728 words = %t1%0 msec
>&2 echo Lookup time for %cnt% inputs = %t2%0 msec
exit /b 

:elapsed  t1  t2  rtn
setlocal
for /f "tokens=1-8 delims=:., " %%a in ("!%~1: =0! !%~2: =0!") do (
  set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, t2=(((1%%e*60)+1%%f)*60+1%%g)*100+1%%h-36610100, tDiff=t2-t1"
)
if !tDiff! lss 0 set /a tDiff+=24*60*60*100
endlocal & set "%~3=%tDiff%"
exit /b

<强> Aacini.bat

@echo off
setlocal EnableDelayedExpansion

:: Define list
set "base=andy bay cay daddy day easy fly gladly happily inky jay key lay may nay ornery pray quay randomly ray say truancy urgency vacancy way xray yesterday zesty "
for %%L in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set "list=!list! !base: =%%L !"

:: Measure preprocessing time
set "t1_0=%time%"
for %%w in (%list%) do (
  set "word=%%w"
  for /F %%l in ("!word:~0,1!") do set "subList[%%l]=!subList[%%l]! %%w"
)
set "t1_1=%time%"

:: Measure lookup time
set /a cnt=0
set "t2_0=%time%"
:START
echo(
set "INPUTWORD="
set /p "INPUTWORD=>Enter a word: "
if not defined INPUTWORD goto :done
set /a cnt+=1
set lastLetter=%INPUTWORD:~-1%
if defined subList[%lastLetter%] (
  for /F "tokens=1*" %%a in ("!subList[%lastLetter%]!") do (
    echo My word = %%a
    set "subList[%lastLetter%]=%%b"
  )
) else (
  echo My word not found in list
)
goto START

:done
set "t2_1=%time%"
call :elapsed t1_0 t1_1 t1
call :elapsed t2_0 t2_1 t2
>&2 echo Preprocessing time for 728 words = %t1%0 msec
>&2 echo Lookup time for %cnt% inputs = %t2%0 msec
exit /b 

:elapsed  t1  t2  rtn
setlocal
for /f "tokens=1-8 delims=:., " %%a in ("!%~1: =0! !%~2: =0!") do (
  set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, t2=(((1%%e*60)+1%%f)*60+1%%g)*100+1%%h-36610100, tDiff=t2-t1"
)
if !tDiff! lss 0 set /a tDiff+=24*60*60*100
endlocal & set "%~3=%tDiff%"
exit /b

- 测试运行结果 -

D:\test>dbenham <test.txt >dbenham.txt
Preprocessing time for 728 words = 10 msec
Lookup time for 551 inputs = 1610 msec

D:\test>dbenham <test.txt >dbenham.txt
Preprocessing time for 728 words = 00 msec
Lookup time for 551 inputs = 1600 msec

D:\test>dbenham <test.txt >dbenham.txt
Preprocessing time for 728 words = 00 msec
Lookup time for 551 inputs = 1610 msec

D:\test>dbenham <test.txt >dbenham.txt
Preprocessing time for 728 words = 00 msec
Lookup time for 551 inputs = 1590 msec

D:\test>dbenham <test.txt >dbenham.txt
Preprocessing time for 728 words = 00 msec
Lookup time for 551 inputs = 1620 msec

D:\test>aacini <test.txt >aacini.txt
Preprocessing time for 728 words = 100 msec
Lookup time for 551 inputs = 1600 msec

D:\test>aacini <test.txt >aacini.txt
Preprocessing time for 728 words = 110 msec
Lookup time for 551 inputs = 1540 msec

D:\test>aacini <test.txt >aacini.txt
Preprocessing time for 728 words = 90 msec
Lookup time for 551 inputs = 1560 msec

D:\test>aacini <test.txt >aacini.txt
Preprocessing time for 728 words = 110 msec
Lookup time for 551 inputs = 1580 msec

D:\test>aacini <test.txt >aacini.txt
Preprocessing time for 728 words = 110 msec
Lookup time for 551 inputs = 1580 msec

D:\test>fc dbenham.txt aacini.txt
Comparing files dbenham.txt and AACINI.TXT
FC: no differences encountered

我平均每个脚本的5个时序,并将查找时间除以551以获得一次迭代的时间。