检查字符串是否带引号并在字符串中添加引号的问题

4

我正在尝试通过检查字符串的第一个和最后一个字符来判断该字符串是否被引用。但是当检查引号时,我的脚本会失败,输出如下: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.

你的脚本中有两个“大”的错误。
  1. 将 set s=^"text^" 简单地写成 set s="text" 即可,无需使用 ^ 字符
  2. DOS 中不存在 AND 条件运算符
- schlebe
5个回答

10

我纠正了你遇到的语法错误,可能是因为错误的转义序列导致的。根据这份文档,你应该使用""而不是^"。但即使这样,它对我也没有起作用,处理双引号有点棘手。

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

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"
)

4
你的回答是有效的,这很好。Windows 命令提示符有些麻烦! - Angus Comber
@AngusComber:“Windows cmd 有点麻烦!”这简直是本十年的轻描淡写啊! :D - antred

3
批处理中没有 AND 这个命令。请使用。
if var1==value1 if var2==value2 echo both ok

相反。


3
@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!
)

0

在编程中,必须使用 ^" 来比较双引号字符 "

set s=Your-Quoted-or-NOT-Quoted-String
if ^%s:~0,1%==^" if ^%s:~-1%==^" (command)

注意: 比较变量%s:~0,1%%s:~-1%的操作也必须以^为前缀。

示例:

@echo OFF

set s="Quoted"
call :test
set s=Normal
call :test
set s=In"String
call :test
set s="Left Quoted
call :test
set s=Right Quoted"
call :test

goto :exit

:test

echo ^>^> s = %s%
set bQuoted=FALSE
if ^%s:~0,1%==^" if ^%s:~-1%==^" set bQuoted=TRUE

if %bQuoted%==TRUE (
    echo ^>^>   string is quoted
) else (    
    echo ^>^>   string is NOT quoted
)

exit /B

:exit

输出显示

D:\>call testquote.bat
>> s = "Quoted"
>>   string is quoted
>> s = Normal
>>   string is NOT quoted
>> s = In"String
>>   string is NOT quoted
>> s = "Left Quoted
>>   string is NOT quoted
>> s = Right Quoted"
>>   string is NOT quoted

-1

通过对环境变量的值进行区分大小写的字符串比较,可以非常简单地检查一个环境变量(如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行一样不带引号引用环境变量值。

其他答案包含了易于检查分配给环境变量的字符串是否被括在"中的解决方案,但它们都没有处理罕见的用例,即分配给环境变量的字符串只有一个",无论是在开头还是结尾,或者分配给环境变量的字符串根本只有一个字符,甚至可能是"

批处理文件的作者很容易控制分配给环境变量的字符串在批处理文件中的外观。但是,如果通过参数字符串将字符串传递给批处理文件或提示用户输入分配给环境变量的字符串,则必须使用附加代码使批处理文件执行失误安全,以防止错误的用户输入或参数字符串。

例如:

@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 命令时重新设置该目录为当前目录(如果仍然存在)。

禁用延迟环境变量扩展,否则传递给批处理文件的参数中包含一个或多个感叹号的情况下,该演示批处理文件会处理错误。任何文件/文件夹名称都可以包含一个或多个字符!

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

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+2或在按下2键时启用了CapsLock,并且用户过快地按下了RETURNENTER以执行命令行。

重要的是要知道,在批处理文件中无法传递包含"并且cmd.exe应该解释为文字字符的参数字符串。Linux shell解释器通过在参数字符串周围使用其他引号来支持此功能,但Windows cmd.exe不支持。

在大多数批处理文件中,只使用"%~1",这在命令提示窗口中运行call /?时的帮助输出中有所解释。这对于大多数用例都有效,但对于某些情况则无效,可以通过上述七个示例测试得出。

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

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

环境变量FirstArgument被定义为第二个、第三个和第四个示例,传递的参数字符串中没有双引号。

但是,如果参数字符串开头没有",则cmd.exe在使用%~1时不会删除参数字符串末尾的"。因此,对于非常不寻常的第五个用例,需要额外的代码来处理这样的参数字符串,以便在不引起后续批处理文件处理退出语法错误的情况下正确处理。

第五个用例的解决方案是,如果定义了环境变量FirstArgument,则显式地从分配给该环境变量的字符串中删除所有"

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

非常重要的是,将环境变量FirstArgument的赋值使用命令SET的参数variable=value时要用双引号括起来。仅使用set FirstArgument=%~1不是安全的。为什么要使用set "variable=value",例如在此处中有解释。

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

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

  • 什么都不输入或
  • 输入一个包含一个或多个"的字符串和/或
  • 输入一个包含操作符如&<>|的字符串。

set /P命令行上指定的环境变量在提示之前要么未定义,要么已经存在,如果用户只是按下RETURNENTER键,则仍未修改。

因此,在提示用户之前定义一个环境变量并提供有用的默认字符串,或者在set /P命令行之后立即使用if defined variable条件检查用户是否输入了任何内容,并相应地处理此用例,这是一个好习惯。

在演示代码中,环境变量UserInput在提示之前以单个"作为值进行定义。因此,如果用户没有输入任何内容,则环境变量UserInput仍然定义为只有"作为值。

set /P 命令行会从用户输入的字符串中去除所有的 " 。因此,在这个命令行之后,环境变量 UserInput 可能已经不存在了。在处理此类情况时,应始终考虑到这一点。最好使用通常的 if defined variable 来处理移除所有双引号后环境变量不再存在的情况。

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

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

但是,有时需要输出分配给环境变量的字符串,例如文件或带路径的文件夹名称,而无需将环境变量引用括在双引号中,以便在控制台窗口或文件中使用 ECHO 命令输出。

这很棘手,因为文件/文件夹名称可能包含被 cmd.exe 解释为运算符的字符,例如 & ,或者在启用延迟环境变量扩展时被解释为环境变量引用的起始/结束符号,例如 !

第三个参数示例非常适合测试批处理文件,因为文件名以两个前导空格开头,接下来是一个分号和一个百分号,还包含一个“&”符号和一个感叹号。任何文件/文件夹名称都可以使用批处理文件进行处理,必须编写非常好的代码来正确处理这样的文件名。

演示代码输出参数字符串或用户输入,而不使用双引号,因此使用临时延迟环境变量扩展来避免传递给批处理文件或用户输入的字符串最终修改由cmd.exe执行的ECHO命令行。通过测试演示批处理文件可以看到,非常不寻常的文件名C:\Temp\ ;%Development & Test!.txt在不引起任何问题的情况下输出而不带双引号。

当然,将未知一致性的文件/文件夹名称用双引号括起来输出会更容易,因此更好。因此,每个使用ECHO打印从文件系统直接读取或作为参数传递给批处理文件或由用户在提示符上输入的包含文件/文件夹名称信息的批处理文件都应该更好地用双引号括起来。这样,用户就更容易看到文件/文件夹名称的开头和结尾,特别是如果文件/文件夹名称没有路径并且有前导空格。


1
你没有回答问题,但我认为问题本身更像是一个XY问题。而你展示了一个正常使用情况的解决方案,你的解释非常详细,谢谢! - jeb
@jeb 谢谢。能够得到像你这样的批处理专家的回复真是太好了。尽管 Angus Comber 没有就他的代码提出具体问题,但我现在也添加了两个代码示例来回答这个问题。 - Mofi

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