从具有分隔符随机数的字符串中获取变量 [cmd]

Get variable from string with random numbers of delimiter [cmd]

我有一个包含许多分隔符“_”的文件夹:text4_text5_text6_text7_2000-01-02

我需要从中创建 2 个变量。第一个是从文件夹名称到最后一个分隔符的所有内容。第二个在最后一个分隔符之后:

日期我有这个代码:

SET DIR = text4_text5_text6_text7_2000-01-02
FOR %%a in (%DIR:_= %) do set DATE=%%a

但我不知道在 %DATE% 之前将 %NAME% 其他所有内容都考虑在内。

我将不胜感激。

您可以将所有值放入字符串数组中。数组的最后一个值必须是 %date%.

@ECHO OFF
SET name=text4_text5_text6_text7_2000-01-02
SET /A id=0
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%a in (%name:_= %) DO (
SET /A id+=1
SET arr[!id!]=%%a
)

REM PRINT ALL VALUES WHERE %id% IS THE LAST ARRAY NUMBER
FOR /L %%i in (1,1,%id%) DO @ECHO !arr[%%i]!

REM PRINT ONLY DATE
@ECHO !arr[%id%]!

ENDLOCAL

如果格式如您所述,最后一个 _ 始终包含以下日期:

@echo off
setlocal enabledelayedexpansion
set "name=text4_text5_text6_text7_2000-01-02"
for %%i in (%name:_= %) do set "mydate=%%i"
set "restofline=!name:%mydate%=!"
echo %restofline:~0,-1% %mydate%

此处 %mydate% 是包含日期的变量,%restofline% 包含其余部分。

这里有一个应用有时 so-called 代码注入技术的方法:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

rem // Define (non-empty) input string here:
set "name=text4_text5_text6_text7_2000-01-02"

rem // Clear variables:
set "rest=" & set "last="
rem // Split off the last `_`-separated item using the code injection technique:
set "rest=%name:_=" & (if defined last set "rest=!rest!_!last!") & set "last=%"

rem // Return result:
set name
set rest
set last

endlocal
pause

相关的控制台输出如下:

name=text4_text5_text6_text7_2000-01-02
rest=text4_text5_text6_text7
last=2000-01-02

要了解它是如何工作的,请将 @echo off 更改为 @echo on 并检查控制台输出。此方法基于 sub-string substitution, and it requires delayed variable expansion.

请注意,如果字符串包含 !^"

,此方法将失败

注意,多个连续的分隔符合并为一个,因此像 abc__def__01 这样的字符串将被拆分为 abc_def01。为避免这种情况并保留分隔符,请将核心代码更改为:

rem // Clear variables:
set "rest=" & set "last=" & set "flag="
rem // Split off the last `_`-separated item using the code injection technique:
set "rest=%name:_=" & (if defined flag (set "rest=!rest!_!last!") else set "flag=#") & set "last=%"

有关此方法的更多信息,请参阅 split string into substrings based on delimiter [DosTips]

这是一种基于您的代码并使用标准 for 循环的方法:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

rem // Define (non-empty) input string here:
set "name=text4_text5_text6_text7_2000-01-02"

rem // Reset variables:
set "rest=_" & set "last="
rem // Split off the last `_`-separated item using a `for` loop:
for %%a in ("%name:_= %") do (
    rem // This assignment is always one iteration behind:
    if defined last set "rest=!rest!_!last!"
    rem // This value is available for the next iteration:
    set "last=%%a"
)
rem // Strip off leading `__`:
set "rest=%rest:~2%"

rem // Return result:
set name
set rest
set last

endlocal
pause

请注意,对于包含 wildcards 的字符串,如 ?*<>,此方法将失败;此外,!^" 不得出现在字符串中。

为了至少避免字符串中的 !^" 出现问题,请改用这个更健壮但更复杂的代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define input string here:
set "name=text4_text5_text6_text7_2000-01-02"

rem // Reset variables:
set "rest=_" & set "last=" & set "flag="
rem // Double quotes to avoid issues with such:
setlocal EnableDelayedExpansion
set "name=!name:"=""!^" & rem ^"
rem // Split off the last `_`-separated item using a `for` loop:
if defined name for %%a in ("!name:_=" "!") do (
    rem // Use `for /F` to transfer string beyond `endlocal` barrier:
    for /F "delims=" %%b in ("!rest!_!last!") do (
        rem // This assignment is always one iteration behind:
        endlocal & if defined flag set "rest=%%b"
    )
    rem // This value is available for the next iteration:
    set "last=%%~a" & set "flag=#"
    rem // Toggle delayed expansion to avoid issues with `!` and `^`:
    setlocal EnableDelayedExpansion
)
rem // Revert doubling of quotes:
set "rest=!rest:""="!^" & rem ^"
if defined last set "last=!last:""="!^" & rem ^"
rem // Strip off leading `__`:
set "rest=!rest:~2!"

rem // Return result:
set name
set rest
set last
endlocal

endlocal
pause

cmd batch-file on windows 中执行此操作的一种方法是在 PowerShell 中使用正则表达式。如果您使用的是受支持的 Windows 系统,则会安装 PowerShell。

请注意,我将结果变量名称 DATE 更改为 THE_DATE。 DATE 是 cmd 中的自动变量,不应单独使用。

C:>type getlastpart.bat
@ECHO OFF
SET "NAME=text4_text5_text6_text7_2000-01-02"
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
    "'%NAME%' -match '(.*)_(.*)' | Out-Null; $matches[2]"') DO (SET "THE_DATE=%%~A")
ECHO THE_DATE is set to "%THE_DATE%"

C:>CALL getlastpart.bat
THE_DATE is set to "2000-01-02"

C:>echo %THE_DATE%
2000-01-02

我认为这是最简单的方法:

@echo off
setlocal EnableDelayedExpansion

set "dir=text4_text5_text6_text7_2000-01-02"

set "name="
set "last=%dir:_=" & set "name=!name!_!last!" & set "last=%"
set "name=!name:~1!"

echo name="%name%"
echo date="%last%"

此方法通过一个简单的子字符串替换来产生 几个 命令。您可能会通过删除 @echo off 行并在屏幕上查看已执行的代码来欣赏它。有关此方法的进一步说明,请参阅 this thread.


如果你想要更标准的方法,那么这个很简单:

@echo off
setlocal EnableDelayedExpansion

set "dir=text4_text5_text6_text7_2000-01-02"

for %%a in ("%dir:_=.%") do set "last=%%~Xa"
set "last=%last:~1%"
set "name=!dir:_%last%=!"

echo name="%name%"
echo date="%last%"