检查字符串是否被引号并将引号添加到字符串的问题

Problems checking if string is quoted and adding quotes to string

我试图通过检查字符串的第一个和最后一个字符来检查字符串是否被引用。但是我的脚本在检查报价时失败了,请参阅输出:AND was unexpected at this time。下面。

代码

@echo off

set mystring=Non quoted string

set myquotedstring=^"My quoted string^"

echo mystring: %mystring%

echo myquotedstring: %myquotedstring%

set result=%mystring:~0,1%

echo first character of non quoted string is: %result%

set result=%mystring:~-1%

echo last character of non quoted string is: %result%

if %mystring:~0,1%u==^" AND %mystring:~-1%==^" (
   echo this string is NOT quoted
   set newstring=^"Non quoted string^"
   echo newstring: %newstring%
)

set result=%myquotedstring:~0,1%

echo first character of quoted string is: %result%

set result=%myquotedstring:~-1%

echo last character of quoted string is: %result%

if %myquotedstring:~0,1%u==^" AND %myquotedstring:~-1%==^" (
   echo this string is quoted
)

这是我得到的输出

mystring: Non quoted string
myquotedstring: "My quoted string"
first character of non quoted string is: N
last character of non quoted string is: g
this string is NOT quoted
newstring: "Non quoted string"
first character of quoted string is: "
last character of quoted string is: "
AND was unexpected at this time.

更新

我现在意识到我不能使用 AND。但是即使我删除我也有问题。

例如

if %mystring:~0,1%u==^" if %myquotedstring:~-1%==^" (
   echo this string is NOT quoted
   set newstring=^"Non quoted string^"
   echo newstring: %newstring%
)

我明白了

The syntax of the command is incorrect.

批量没有AND。使用

if var1==value1 if var2==value2 echo both ok

相反。

我更正了你遇到的语法错误。这可能是因为错误的转义序列。由于这个 documentation,您应该使用 "" 而不是 ^"。但它对我也不起作用,处理双引号有点棘手。

就个人而言,我在处理字符串之前将 " 替换为 + 或其他一些字符。所以这段代码工作正常:

set myquotedstring="My quoted string"

set firstChar=%myquotedstring:~0,1%
set lastChar=%myquotedstring:~-1%

:: Replace " with +
set firstChar=%firstChar:"=+%
set lastChar=%lastChar:"=+%

if "%firstChar%"=="+" if "%lastChar%"=="+" (
    echo "myquotedstring is quoted"
)

一个非常简单的检查是通过区分大小写的字符串比较环境变量的值(如 mystring 与另一个环境变量(如 MyStringCheck 之前定义的 MyStringCheck 的值 mystring 将所有双引号替换为空字符串,从而删除所有双引号。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "mystring=Non quoted string"
set "myquotedstring="My quoted string""
setlocal EnableDelayedExpansion

set "_StringCheck=!mystring:"=!"
if !mystring! == !_StringCheck! (
       echo mystring is defined with NOT quoted string: !mystring!
) else echo mystring is defined with quoted string: !mystring!
set "mystring="!_StringCheck!""

set "_StringCheck=!myquotedstring:"=!"
if !myquotedstring! == !_StringCheck! (
       echo myquotedstring is defined with NOT quoted string: !myquotedstring!
) else echo myquotedstring is defined with quoted string: !myquotedstring!
set "myquotedstring="!_StringCheck!""

rem Output the two environment variables after string checking.
echo/
echo The environment variables mystring and myquotedstring are now:
echo/
set my

endlocal
endlocal

这段代码没有不需要的IF条件:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "mystring=Non quoted string"
set "myquotedstring="My quoted string""
setlocal EnableDelayedExpansion
set "mystring="!mystring:"=!""
set "myquotedstring="!myquotedstring:"=!""
echo The environment variables mystring and myquotedstring are:
echo/
set my
endlocal
endlocal

为什么要检查字符串是否被引号并添加引号?

将字符串分配给不带引号的环境变量并在必须在引用环境变量值时使用批处理文件中的引号几乎总是更好,但在引用环境变量值时不带引号这不像 ECHO 行那样。

其他答案包含轻松检查分配给环境变量的字符串是否包含在 " 中的解决方案,但其中 none 处理分配给字符串的罕见用例环境变量在开头或结尾只有一个 ",或者分配给环境变量的字符串根本只有一个字符,甚至可能是 ".

批处理文件的作者很容易控制分配给环境变量的字符串在批处理文件本身中写入的字符串的外观。但是,如果字符串通过参数字符串传递给批处理文件,或者提示用户输入分配给环境变量的字符串,则必须使用额外的代码来使批处理文件的执行因错误的用户输入或参数而失败。字符串。

示例:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Example for processing an argument.
set "FirstArgument=%~1"
if defined FirstArgument set "FirstArgument=%FirstArgument:"=%"
setlocal EnableDelayedExpansion
echo First argument without quotes is:  !FirstArgument!
endlocal
echo First argument with quotes is:    "%FirstArgument%"

rem Example for processing a user input.
set "UserInput=""
set /P "UserInput=Please enter something: "
set "UserInput=%UserInput:"=%"
setlocal EnableDelayedExpansion
echo User input without quotes is:  !UserInput!
endlocal
echo User input with quotes is:    "%UserInput%"

endlocal

在此示例中,首先所需的执行环境由前两个命令行完全定义:

  • 命令回显模式已禁用
  • 命令扩展已启用
  • 禁用延迟环境变量扩展

命令SETLOCAL在启用命令扩展和禁用延迟扩展之前,根据使用的两个选项,不只是将命令扩展和延迟扩展的当前状态压入堆栈,而是使也是启动批处理文件时已经定义的所有环境变量的副本。这个新创建的环境变量列表用于批处理文件的其余部分。 SETLOCAL 还将当前目录的路径压入堆栈。

批处理文件末尾的命令ENDLOCAL恢复了以前的执行环境,这意味着命令扩展和延迟扩展的状态从堆栈中弹出并进行相应设置。此外,创建的环境变量列表将被丢弃并恢复初始环境变量列表,这意味着环境变量 FirstArgumentUserInput 在此批处理文件处理完成后不再存在,分别在启动时具有初始值启动批处理文件时已经存在的批处理文件。还会从堆栈中弹出当前目录路径,如果在执行命令 ENDLOCAL.

时该目录仍然存在,则该目录将再次设置为当前目录

延迟环境变量扩展被禁用,否则传递给包含一个或多个感叹号的批处理文件的参数将被此演示批处理文件处理错误。任何 file/folder 名称都可以包含字符 ! 一次或多次。

处理传递给批处理文件的参数字符串

Test.cmd这样的批处理文件可以这样启动:

  1. Test.cmd
    批处理文件在没有传递给批处理文件的参数字符串的情况下启动,这意味着 %1 被空字符串替换。
  2. Test.cmd C:\Temp\Example.txt
    批处理文件以未用双引号引起来的参数字符串开头。
  3. Test.cmd "C:\Temp\ ;%Development & Test!.txt"
    批处理文件以用双引号括起来的参数字符串开头。
  4. Test.cmd "C:\Temp\Common File Name.txt
    批处理文件以参数字符串开头,错误地只存在开头的 ",但缺少参数字符串末尾的 "
  5. Test.cmd C:\Temp\FileName.txt"
    批处理文件以参数字符串开头,错误地缺少开头的 ",但存在参数字符串末尾的 "
  6. Test.cmd ""
    批处理文件以空参数字符串开始。如果可执行文件或其他批处理文件启动批处理文件时,通常会发生这种情况,该批处理文件在代码中包含错误,导致批处理文件在第一个参数字符串周围用双引号引起来,但参数字符串丢失。
  7. Test.cmd "
    批处理文件仅以一个双引号字符开头。这可能发生在使用德语或英国键盘的用户想要以 2 作为参数启动批处理文件,但按下 Shift+2CapsLock 已在按下键 2 时启用,用户点击速度太快 RETURNENTER执行命令行。

重要的是要知道,不可能将参数字符串传递给包含 "cmd.exe 应解释为文字字符的批处理文件。 Linux shell 解释器通过在参数字符串周围使用其他引号来支持这一点,但 Windows cmd.exe.

在大多数批处理文件中,只使用 "%~1",由命令提示符 window call /? 中 运行 上的帮助输出解释。这适用于大多数用例,但并非适用于所有用例,因为在使用上述七个示例测试此类批处理文件时可以看出。

发布的批处理文件将第一个参数分配给环境变量 FirstArgument,并让 cmd.exe 删除周围的双引号。

环境变量 FirstArgumentnotfirstsixth 定义的和 last 示例,因为 %~1 在这种情况下被空字符串替换,因此执行 set "FirstArgument=" 导致删除环境变量(如果存在)。

secondthirdfourth[=229=定义了环境变量FirstArgument ] 带有不带双引号的传递参数字符串的示例。

但是如果参数字符串的开头没有 "cmd.exe 不会在使用 %~1 时删除参数字符串末尾的 "。因此,对于非常不寻常的 fifth 用例,需要额外的代码来处理此类参数字符串也可以正确处理,而不会由于语法错误而导致稍后退出批处理文件处理,因为 " 在字符串的末尾。

第五个 用例的解决方案是从分配给环境变量 FirstArgument 的字符串中显式删除所有 "(如果此环境变量已定义)。

需要引用字符串的字符在cmd输出的帮助中列出运行 cmd /?在命令中显示的最后一个帮助页面提示 window 是 space 或这些字符之一 &()[]{}^=;!'+,`~。如果应将参数字符串传递给包含重定向运算符的批处理文件 <>| 被解释为文字字符,例如密码字符串,则参数字符串也必须用双引号引起来。

非常重要的是,对环境变量FirstArgument 的赋值是用双引号括起来的命令SET 的参数variable=value 完成的。只是 set FirstArgument=%~1 的用法并不是万无一失的。例如 here.

解释了为什么使用 set "variable=value"

处理用户在提示时输入的字符串

在批处理文件 set /P 中使用时应像在处理参数字符串时一样小心,因为用户实际上可以输入任何内容。一个用户可以

  • 什么都不输入或
  • 输入包含一个或多个的字符串 " and/or
  • 输入包含 &<>|.
  • 等运算符的字符串

set /P 命令行上指定的环境变量在提示之前不存在时仍然未定义,或者在提示之前已经存在的情况下仍然未修改,以防用户点击提示 RETURNENTER.

出于这个原因,最好在用有用的默认字符串提示用户之前定义一个环境变量,或者在 set /P 命令行之后立即检查 if defined variable 条件(如果用户输入)任何事情并相应地处理这个用例。

环境变量 UserInput 在提示前定义,在演示代码中使用单个 " 作为值。因此,如果用户什么都不输入,环境变量 UserInput 仍然只定义为 " 作为值。

set /P 之后的命令行从用户输入的字符串中删除所有 "。现在的结果可能是在此命令行之后不再定义环境变量 UserInput。应始终考虑到这一点。在删除所有双引号后,通常(再次)使用 if defined variable 来处理不再定义环境变量的这种用例是一种很好的做法。

使用 ECHO 输出环境变量字符串

在将包含环境变量引用 %variable% 本身的参数字符串用双引号括起来时,删除所有双引号后,可以进一步安全地处理分配给环境变量的字符串。

但有时分配给环境变量的字符串,如不带或带路径的文件或文件夹名称,应使用命令 ECHO 输出到控制台 window 或文件并且应该在不将环境变量引用括在双引号中的情况下完成。

这很棘手,因为 file/folder 名称可以包含像 & 这样的字符,在双引号参数字符串之外被 cmd.exe 解释为运算符,或者 ! 被解释为start/end 当前启用延迟环境变量扩展的环境变量引用。

third 参数示例非常适合测试批处理文件,因为文件名以两个前导 space 开头,接下来包含一个分号和一个百分比符号,另外包含一个符号和一个感叹号。有权使用任何 file/folder 名称的批处理文件必须进行非常好的编码才能正确处理此类文件名。

演示代码分别输出用户输入的参数字符串,不带双引号,因此使用临时延迟的环境变量扩展,以避免用户分别输入的传递给批处理文件的字符串修改ECHO 命令行最终由 cmd.exe 执行。测试演示批处理文件可以看出,非常不寻常的文件名C:\Temp\ ;%Development & Test!.txt输出时不带双引号,没有造成任何麻烦。

输出一个 file/folder 未知一致性的名称当然更容易,因此更好,并将其括在双引号中。因此,每个批处理文件打印 ECHO 包含 file/folder 名称的信息直接从文件系统读取或作为参数传递给批处理文件或由用户在提示符下输入应该附上file/folder 名称用双引号括起来更好。然后,用户也更容易看到 file/folder 名称开始和结束的位置,特别是如果 file/folder 名称输出时没有路径且具有前导 spaces.

@echo off
setlocal EnableDelayedExpansion

set mystring=Non quoted string
echo %mystring%
if !mystring:~0^,1!!mystring:~-1! equ "" (
   echo -^> String is quoted
) else (
   echo -^> String not quoted
   set newstring="%mystring%"
   echo New string: !newstring!
)
echo/

set mystring="My quoted string"
echo %mystring%
if !mystring:~0^,1!!mystring:~-1! equ "" (
   echo -^> String is quoted
) else (
   echo -^> String not quoted
   set newstring="%mystring%"
   echo New string: !newstring!
)