如果字符串以

问题描述 投票:0回答:4

我试图弄清楚字符串是否以子字符串开头:

rem GetInput
if "%result%"=="cd *" goto Cd
:Cd
if "%result%"=="cd meow" Echo Going to directory 'meow'...

不幸的是,这并没有在应该循环回到 :Cd 的时候。如何检测字符串是否以

cd 
开头?

batch-file
4个回答
24
投票

如果我理解正确的话,您正在尝试确定

%result%
的值是否以“cd”开头,并且您无法成功使用
*
作为通配符来确定这一点。

有几种不同的方法可以处理这个问题。这是一种方法:您可以检查前两个字符是否等于“cd”:

if /i "%result:~0,2%"=="cd" goto Cd

set /?
有更多相关内容。


5
投票

标题比用例更广泛,这使得通用的starts对于特定问题来说有点矫枉过正——正如Wes所说,对于这个特定问题,你可以只检查前两个字符并检查

cd
.

但是请记住这一点,让我们回答标题中更通用的问题。

通用开头

DOSTips.com的startsWith解决方案看起来相当不错。

:StartsWith text string -- Tests if a text starts with a given string
::                      -- [IN] text   - text to be searched
::                      -- [IN] string - string to be tested for
:$created 20080320 :$changed 20080320 :$categories StringOperation,Condition
:$source https://www.dostips.com
SETLOCAL
set "txt=%~1"
set "str=%~2"
if defined str call set "s=%str%%%txt:*%str%=%%"
if /i "%txt%" NEQ "%s%" set=2>NUL
EXIT /b

更容易阅读的重构? (TL;DR——这就是答案)

这似乎可行,但它并没有真正返回值,而且它的变量名称非常 20 世纪 90 年代。

我破解了这个:

:startsWith
set "haystack1=%~1"
set "needle2=%~2"

if defined needle2 call set "s=%needle2%%%haystack1:*%needle2%=%%"
if /i "%haystack1%" NEQ "%s%" (
    exit /b 0
)
EXIT /b 1

这将在

1
中返回
%errorlevel%
表示“是”、“开始于”,以及
0
表示“否”、“不开始于”。你可能会认为 does-start-with 应该返回
0
来表示“没有错误”。如果您有强烈的感觉,显然欢迎您在实现中交换这些内容。我会选择“零传统上是假的,因此它代表错误的返回值”。 YMMV,🍅🍅

测试实施

这是一个完整的测试示例...

@ECHO OFF

call :startsWith slappy slap
echo %errorlevel%
echo.

call :startsWith slap slappy
echo %errorlevel%
echo.

call :startsWith slappy spam
echo %errorlevel%
echo.

call :startsWith slappy lap
echo %errorlevel%
echo.

call :startsWith spam
echo %errorlevel%
echo.
exit /b 0

:startsWith
set "haystack1=%~1"
set "needle2=%~2"
set "s="

REM I think this is okay b/c if %2 was defined, %1 kinda has to be too.
if defined needle2 call set "s=%needle2%%%haystack1:*%needle2%=%%"

echo needle:   %needle2%
echo haystack: %haystack1%
echo s:        %s%

if /i "%haystack1%" NEQ "%s%" (
    exit /b 0
)
EXIT /b 1

输出

needle:   slap
haystack: slappy
s:        slappy
1

needle:   slappy
haystack: slap
s:        slappyslap
0

needle:   spam
haystack: slappy
s:        spamslappy
0

needle:   lap
haystack: slappy
s:        lappy
0

needle:
haystack: spam
s:
0

这是一个巧妙的技巧。基本上...

  1. 创建一个以
    needle
  2. 开头的新字符串
  3. 如果
    needle
    出现在 haystack 中的
    anywhere
    ,请将
    haystick
    出现在
    needle
    之后出现的部分添加到新字符串中。否则将所有
    haystack
    添加到新字符串中。
  4. 如果这个新字符串与
    haystack
    匹配,你就赢了!不然你就输了

因此,如果针是

slap
,干草堆是
slappy
,那么
%s%
将是
slap
加上[
slap
slappy
之后的所有内容,即...]
py
。这给了我们
slappy
,它与
haystack
中的内容相匹配,我们赢了。

如果针是

spam
并且干草堆是
slappy
%s%
将从
spam
开始,然后,由于
spam
不在
slappy
中,我们添加haystack
all
。这让我们只剩下
spamslappy
,我们就输了。 (
spamslappy
?现在这是喜剧。)

当你寻找 is innot 位于

haystack
开头的东西时,就像我们的
lap
示例一样,这是一个彻底的失败。也就是说,如果针是
lap
并且干草堆是
slappy
%s%
将以
lap
开始,然后,从
lap
slappy
结束的所有内容也给出
py
,我们有
 lap
加上
py
lappy
,这不是
slappy
,我们再次失败,但以一种新的、很酷的方式。


您的批处理语法问题已得到解答(也许)

set "needle2=%~2"
中的波形符是什么?

删除参数引用。命令行参数之前的波浪号(例如

"%~1"
)表示从参数中删除周围的引号。例如,如果
%1
的值为
"Hi"
,则
%~1
将扩展到仅
Hi

call set "s=%str%%%txt:*%str%=%%"
有点复杂。

首先了解冒号(

:
)意味着我们正在使用“字符串替换功能”:

此代码取自同一页面,将

needs
中的
has
替换为
%str

set str=%str:needs=has% 
echo %str%

然后我们需要知道...

“StrToFind”[在

:
之后]可以以星号开头,在这种情况下,它将替换“StrToFind”左侧的所有字符。
...

::Delete the character string 'ab' and everything before it
SET _test=12345abcabc
SET _result=%_test:*ab=% 
ECHO %_result%          =cabc

那就看这个答案

那里的

call
导致了另一层变量扩展,因此有必要[转义]原始的
%
符号,但最终一切都会解决。

现在

call set "s=%str%%%txt:*%str%=%%"
应该有意义了。

该问题的另一个答案表明,DOSTips 中的startsWith 方法比这里的其他答案稍微不那么挑剔......

您可以使用 !,但您必须设置 ENABLEDELAYEDEXPANSION 开关。

我们正在避免这种情况。

然后,最后...

如果您对所有这些神秘规则的疯狂感到震惊,那么您应该学习 PowerShell,这太棒了!

哈! 😏 好的,但是我们仍然可以在不离开批次的情况下完成它。享受吧!


2
投票

这里有一个相对稳健且通用的

startsWith
子例程(有两个示例)。如果字符串以另一个字符串开头,它将错误级别设置为1,如果不是,则将错误级别设置为0。

@echo off
set string1=abc123123
set checker1=abc

call :startsWith %string1% %checker1%
if %errorlevel% equ 1 (
    echo %string1% starts with %checker1%
) else (
    echo %string1% does NOT start with %checker1%
)

set string2=xyz123123 abc

call :startsWith %string2% %checker2%
if %errorlevel% equ 1 (
    echo %string2% starts with %checker2%
) else (
    echo %string2% does NOT start with %checker2%
)




exit /b 0

::::::::::::::::::::::::::::::::::::::::
:::----- subroutine starts here ----::::
:startsWith [%1 - string to be checked;%2 - string for checking ] 
@echo off
rem :: sets errorlevel to 1 if %1 starts with %2 else sets errorlevel to 0

setlocal EnableDelayedExpansion

set "string=%~1"
set "checker=%~2"
rem set "var=!string:%~2=&echo.!"
set LF=^


rem ** Two empty lines are required
rem echo off
for %%L in ("!LF!") DO (
    for /f "delims=" %%R in ("!checker!") do ( 
        rem set "var=!string:%%~R%%~R=%%~L!"
        set "var=!string:%%~R=#%%L!"
    )
)
for /f "delims=" %%P in (""!var!"") DO (
    if "%%~P" EQU "#" (
        endlocal & exit /b 1
    ) else (
        endlocal & exit /b 0
    )
)
::::::::::::::::::::::::::::::::::::::::::::::::::

0
投票

我找到了一个更简单的答案。

set result=cd meow

echo %result%|>nul findstr /b /l "cd "
if %ERRORLEVEL% EQU 0 (echo success) else (echo fail)

您还可以使用

/e
标志检查渲染器。正则表达式也带有
/r

警告:

findstr
很慢。最好不要经常打电话。

© www.soinside.com 2019 - 2024. All rights reserved.