如何在批处理文件中使用特殊字符 - Choice命令

3

我想在我的选择命令中添加特殊字符,比如 <| ,我该怎么做?

这是我的旧代码:

CHOICE /C ABCDEFGHIJKLMNOPQRSTUVWXYZ0134567928 /N /M "Press 8 ...."

我希望您能够将其翻译成类似以下的内容:

CHOICE /C `~,.<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ0134567928 /N /M "Press 8 ...."

任何帮助都将不胜感激,谢谢。

编辑:由于有些人可能会问我为什么需要这么多选择,我在这里回答。这是因为按下无效的选项会发出一个恼人的哔声,我不想听到。因此我提出了这个问题。


1
你需要转义或引用特殊字符。如果你这样做,会看到这个消息 - "有效的选择字符是:a-z,A-Z,0-9和128到254的ASCII值"。 - user6017774
@Noddles 嗯,这个问题已经在下面得到了回答。 - user6250760
1
你的意思是什么。你的代码有误(缺少三个双引号),所以我修正了它,以便向你显示关于其余错误代码的错误消息。MSDos中的choice需要按下Escape键。 - user6017774
3个回答

5

CHOICE命令只允许使用字母数字字符,以及使用128-254十进制字节代码的扩展ASCII字符。

我基于一种使用REPLACE的黑客手段编写了纯批处理替代CHOICE的工具。我的:getKey程序可以接受大多数字符,并允许您指定允许使用的字符,并将捕获的字符放入所选变量中 - 比操作ERRORLEVEL方便得多。

我最初在http://www.dostips.com/forum/viewtopic.php?f=3&t=7396上发布了这个程序。该链接还有一个更复杂的程序,可以读取绝对任何键值,包括NULL,以及允许输入掩码字符串(为每个字符显示星号)的程序。

下面是:getKey程序以及示例。如果要使键区分大小写,请删除/I开关。完整的文档已嵌入到脚本中。

编辑 - 我已更新版本2.0的代码,支持指定提示语,并且可以使有效键列表区分大小写。唯一无法模仿的CHOICE功能是默认回应超时选项。我看不出有任何合理的方法来提供超时选项。

@echo off
setlocal enableDelayedExpansion

set "valid=0`~,.<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ0134567928"
call :getKey /p "Press 8 ...." key valid /i
echo(
echo You pressed !key!
exit /b

::getKey  [/P "Prompt"]  KeyVar  [ValidVar [/I]]
::
:: Read a keypress representing a character between 0x00 and 0xFF and store the
:: value in variable KeyVar. Null (0x00), LineFeed (0x0A), and Carriage Return
:: (0x0D) will result in an undefined KeyVar. On Windows 10, Ctrl-Z (0x1A) will
:: also result in an undefined KeyVar. The simplest way to get an undefined
:: KeyVar is to press the [Enter] key.
::
:: The optional /P parameter is used to specify a "Prompt" that is written to
:: stdout, without a newline. Also, the accepted character is ECHOed after the
:: prompt if the /P option was used.
::
:: The optional ValidVar parameter defines the values that will be accepted.
:: If the variable is not given or not defined, then all characters are accepted.
:: If given and defined, then only characters within ValidVar are accepted. The
:: first character within ValidVar should either be 0, meaning ignore undefined
:: KeyVar, or 1, meaning accept undefined KeyVar. The remaining characters
:: represent themselves. For example, a ValidVar value of 0YN will only accept
:: uppercase Y or N. A value of 1YN will additionally accept [Enter] etc.
::
:: If ValidVar is followed by the optional /I switch, then case of standard
:: English letters is ignored. The case of the pressed key is preserved in
:: the result, but English letters A-Z and a-z are not rejected due to case
:: differences when the /I switch is added.
::
:: Any value (except null) may be entered by holding the [Alt] key and pressing
:: the appropriate decimal code on the numeric keypad. For example, holding
:: [Alt] and pressing numeric keypad [1] and [0], and then releasing [Alt] will
:: result in a LineFeed.
::
:: The only way to enter a Null is by holding [Ctrl] and pressing the normal [2]
::
:: An alternate way to enter control characters 0x01 through 0x1A is by holding
:: the [Ctrl] key and pressing any one of the letter keys [A] through [Z].
:: However, [Ctrl-A], [Ctrl-F], [Ctrl-M], and [Ctrl-V] will be blocked on Win 10
:: if the console has Ctrl key shortcuts enabled.
::
:: This function works properly regardless whether delayed expansion is enabled
:: or disabled.
::
:: :getKey version 2.0 was written by Dave Benham, and originally posted at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=7396
::
:: This work was inspired by posts from carlos and others at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=6382
::
:getKey
setlocal disableDelayedExpansion
if /i "%~1" equ "/P" (
  <nul set /p ^"=%2"
  shift /1
  shift /1
  set "getKey./P=1"
) else (
  set "getKey./P="
)
:getKeyRetry
(
  endlocal&setlocal disableDelayedExpansion
  (for /f skip^=1^ delims^=^ eol^= %%A in ('replace.exe ? . /u /w') do for /f delims^=^ eol^= %%B in ("%%A") do (
    endlocal
    if "%%B" equ "" (set "%1=^!") else set "%1=%%B"
    setlocal enableDelayedExpansion
  )) || (
    endlocal
    set "%1="
    setlocal enableDelayedExpansion
  )
  set "getKey./P=%getKey./P%"
  if defined %1 (set "getKey.key=!%1!") else set "getKey.key=x"
)
(
  if "!%2!" neq "" (
    if defined %1 (
      set "getKey.mask=!%2:~1!"
      if not defined getKey.mask goto :getKeyRetry
      if /i "%~3" equ "/I" (
        if "!%1!" equ "=" (
          set "getKey.mask=a!getKey.mask!"
          for /f "delims=" %%A in ("!getKey.mask!") do if /i "!getKey.mask:%%A=%%A!" equ "!getKey.mask!" goto :getKeyRetry
        ) else for /f delims^=^ eol^= %%A in ("!%1!") do if "!getKey.mask:*%%A=!" equ "!getKey.mask!" goto :getKeyRetry
      ) else (
        for /f tokens^=1*^ eol^=^%getKey.key%^ delims^=^%getKey.key% %%A in ("!getKey.mask!!getKey.mask!") do if "%%B" equ "" goto :getKeyRetry
      )
    ) else if "!%2:~0,1!" equ "0" goto :getKeyRetry
  )
  if defined getKey./P echo(!%1!
  exit /b
)

2
@SteveFest,我猜漏了一个=号:<nul set /p ="按键[A|>]: " - aschipfl
@dbenham 不好意思晚回了……我最近又用了这个代码。但是有没有办法像choice命令中的/t标志一样添加一个超时选项? - user6250760
@SteveFest - 抱歉,不行。 - dbenham
@dbenham 最终我创建了一个VB脚本来模拟按键,以便在我的超时时间到达后按下一个键。 - user6250760
@user6250760,你能发布一下你的VB脚本吗?它可以实现超时功能吗?可以提供一个Pastebin链接吗? - Skip R
显示剩余2条评论

2

使用Choice命令是不行的。

如果你尝试使用Choice命令输入无效字符,会收到一个提示信息。例如(要使用上箭头'^'转义管道符'|',因为它是cmd的特殊字符):

CHOICE /C ^|

返回:

错误:无效的选择。有效的选择字符是:a-z,A-Z,0-9和128到254的ASCII值。

可能的解决方法:

您可能可以使用SET来实现您的需求,但这样做会在批处理脚本中使用变量时可能引起问题。您将需要在使用这些变量的任何地方之前使用转义字符caret (^)。

此解决方法还要求用户在进行选择后按回车键。

@ECHO OFF
Choose one:
ECHO.
ECHO ^| - 1
ECHO ^> - 2
ECHO A - 3
ECHO ^" - 4
ECHO ^^ - 5
SET /P KeyPressed=Choice? [^|^>A]
IF [^%KeyPressed%]==[^|] ECHO 1 && GOTO END
IF [^%KeyPressed%]==[^>] ECHO 2 && GOTO END
IF [^%KeyPressed%]==[^A] ECHO 3 && GOTO END
IF [^%KeyPressed%]==[^"] ECHO 4 && GOTO END
IF [^%KeyPressed%]==[^^] ECHO 5 && GOTO END
ECHO None of them.


:END

1
如果您在比较中使用引号而不是括号,则无需转义。例如:if“% KeyPressed%”==“|” - aschipfl
@aschipfl - 如果 %KeyPressed% == " - Jeff Block
1
你差点骗到我了!;-) 我会把 set "KeyPressed=%KeyPressed:"=""%" 放在 set /P 后面来将 " 倍增,然后写成 if "%KeyPressed%"=="""" ... - aschipfl

-1
ShowMenu

Sub ShowHelpMenu
    outp.writeline " -----------------------------------------------------------------------------"
    outp.writeblanklines(1) 
    outp.writeline " Menu"
    outp.writeline " ----"
    outp.writeblanklines(1) 
    outp.writeline "  1 Help              2 HTML Help          3 Version           4 History"
    outp.writeblanklines(1) 
    outp.writeline "  5 Exit"
    outp.writeblanklines(1) 
    outp.write "Filter>"
End Sub

'=============================================
Sub ShowMenu
    Do
        ShowHelpMenu
        Answ=Inp.readline
        If Answ = "1" Then
            ShowGeneralHelp "TEXT"
        Elseif Answ = "2" Then
            ShowGeneralHelp "HTML"
        Elseif Answ = "3" Then
            Version
        Elseif Answ = "4" Then
            History
        Elseif Answ = "5" Then
            Exit Do
        End If
    Loop
End Sub

这是一个VBS文件。


抱歉,我想要一个批处理文件的答案,而你给出的是VBS的答案。 - user6250760
我实际上修剪了选择命令,但忘记添加引号。我正在处理另一件需要不断按键盘的事情。我认为 set /p 无法满足这个需求。 - user6250760
我使用这么多选项是因为我不希望在选择无效选项时出现蜂鸣声。 - user6250760
让我们在聊天中继续这个讨论 - user6250760

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接