【问题标题】:如何将用户输入的字符串与批处理文件中的特殊字符进行比较?
【发布时间】:2022-01-21 08:16:41
【问题描述】:

问题:如何比较用户输入的字符串包含特殊字符,例如 Windows Batch 中的7^7%7&7=7"7!7

未完成的代码:

set/p str1=URL: 
rem if %str1%==7^7%7&7=7"7!7 (  // syntax error
rem if "%str1%"=="7^^7%%7^&7=7^"7!7" (  // still syntax error
    echo Nice
) else (
    echo Bad
)

预期输出:

> URL: 7^7%7&7=7"7!7
> Nice
> URL: 42
> Bad

附言用户输入的字符串在实际情况下实际上是有效的 url,因此所有valid url characters 都是可能的输入,对于与此问题类似的更一般情况,包括引号。

【问题讨论】:

  • = 符号是批量子串修改所采用的搜索替换使用的命令标记,不能使用子串修改替换。考虑查看dave benhams jrepl.bat
  • 为什么需要=-符号分隔?我问是因为我怀疑X/Y Problem。无论如何,您不能使用sub-string substitution,因为=-符号分隔搜索和替换字符串;但是,您可以使用 sub-string expansiongoto 循环遍历字符串的每个字符并用替换的字符重新组合字符串...
  • @aschipfl 你说得对,我在我的问题中添加了太多误导和无用的信息,让我考虑一下并清理它

标签: batch-file variables cmd escaping string-comparison


【解决方案1】:

主要问题是不平衡的引号。条件:

if "%str1%"=="7^7%%7&7=7"7!7^" (
    echo Nice
) else (
    echo Bad
)

只要变量 str1 本身不包含(不平衡的)引号,就不应再自行返回语法错误(假设 delayed variable expansion 已禁用)。如您所见,%-symbol 必须加倍,独立于引号,但其他特殊字符只能在出现在引号之外时进行转义。最后一个引号被转义,因此无法识别。

但是如果你在提示符中输入7^7%7&7=7"7!7 仍然会失败,因为str1 中的引号,因为(立即)变量扩展发生在检测到特殊字符之前。防止条件失败的唯一方法,独立于用户输入,您必须使用延迟变量扩展:

set /P str1="URL: "
rem // At first, enable delayed variable expansion:
setlocal EnableDelayedExpansion
rem /* Then apply it by enclosing variables with `!!` rather than `%%`;
rem    there are now even more complex escape sequences necessary though: */
if "!str1!"=="7^^7%%7&7=7"7^^!7^" (
    echo Nice
) else (
    echo Bad
)
endlocal

您可能已经认识到,比较的正确表达式现在看起来很奇怪,因为延迟扩展可能需要一些额外的转义,具体取决于表达式是否包含感叹号。

为了避免需要这种相当混乱和难以辨认的转义表达式,请先将比较字符串分配给一个变量,同时延迟扩展仍然被禁用:

set /P str1="URL: "
rem /* Predefine comparison expression; you always have to double `%`-symbols,
rem    and you still need to escape some special characters that appear unquoted,
rem    but escaping sequences do not depend on whether or not there is a `!`: */
set "cmp1=7^7%%7&7=7"7!7^"
rem // At first, enable delayed variable expansion:
setlocal EnableDelayedExpansion
rem // Then apply it by enclosing variables with `!!` rather than `%%`:
if "!str1!"=="!cmp1!" (
    echo Nice
) else (
    echo Bad
)
endlocal

【讨论】:

  • 它运行良好,谢谢!我不知道延迟扩张也会影响逃跑,现在感觉更像是人类的东西。但我不确定我明白你的意思,尤其是引用部分,当你分配cmp1时,它是7^7%%7&7=7"7!7^",而我认为它是7^7%%7&7=7^"7!7",为什么它是应该转义的最后一个引用?如果我希望用户输入"test",如何分配cmp1
  • @Byzod 引用的最后转义不是必需的。你的第二个问题:是set "cmp="test""
  • 您需要注意cmd.exe 每次遇到未转义的引号时都会从左到右读取该行并切换引号模式(最初关闭);当引用模式打开时,转义不再起作用,因为转义字符 ^ 被逐字处理,这使得转义无论如何都没有必要;当引号模式关闭时,您需要转义特殊字符。因此,当引号模式打开时,您无法转义引号......
  • 如果出现不平衡的报价,我倾向于转义最后一个,以便在关闭报价模式的情况下结束行,这在这种特殊情况下是不必要的,因为没有任何后续内容,但这是必需的一旦有进一步的命令;例如set "quote="^" & set "caret=^"
  • @Byzod 没错,!cmp! 不再被解释,但%cmp% 就像直接打字一样,规则你可以看How does the Windows Command Interpreter (CMD.EXE) parse scripts?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 2015-11-06
相关资源
最近更新 更多