在最后 space 之后将变量减少到所有

Pare down a variable to all after last space

我有以下内容,将文件夹名称 (FOLDER) 缩减为仅第一个 space (tmpFOLDER) 之前的所有文本。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B
for %%I in (..) do set "FOLDER=%%~nxI"
for /f "tokens=1 delims= " %%a in ("%FOLDER%") do set tmpFOLDER=%%a

ECHO %FOLDER%
ECHO %tmpFOLDER%

popd
endlocal

主要请求:

有没有办法反过来做?

文件夹名称 (%FOLDER%):史密斯 - 约翰

当前示例 (%tmpFOLDER%):Smith

所需示例 (%tmpFOLDER%):John

中学:

有没有办法对文件执行此操作,同时忽略任何文件类型(即 .txt)?

文件名 (%FILE%):“史密斯 - John.txt”

示例当前 (%tmpFILE%):史密斯

所需示例 (%tmpFILE%):John

遍历文件或目录名的话for /F loop cannot extract tokens counted from the end of a string. However, you could use a standard for loop:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Retrieve base name of grand-parent directory of this script:
for /D %%I in ("%~dp0..") do set "FOLDER=%%~nI"
echo Old name: "%FOLDER%"

set "PREV=" & set "COLL="
rem /* Unnecessary loop iterating once and returning the whole directory name;
rem    it is just here to demonstrate how to handle also more than one names: */
for /F "delims= eol=|" %%L in ("%FOLDER%") do (
    rem // Store current name strng and reset some interim variables:
    set "NAME=%%L" & set "PREV=" & set "COLL= "
    rem // Toggle delayed expansion to avoid issues with `!` and `^`:
    setlocal EnableDelayedExpansion
    rem // Ensure to have each space-separated word quoted, then loop through them:
    for %%K in ("!NAME: =" "!") do (
        rem /* Build new buffer by concatenating word from previous loop iteration,
        rem    then transfer it over `endlocal` barrier (localised environment): */
        for %%J in ("!COLL! !PREV!") do (
            rem // Store current word in an unquoted manner:
            endlocal & set "ITEM=%%~K"
            rem // Store current buffer, store current word for next iteration:
            set "COLL=%%~J" & set "PREV=%%~K"
            setlocal EnableDelayedExpansion
        )
    )
    endlocal
)
rem // Retrieve final result:
set "RESULT=%COLL:~3%"
echo New name: "%RESULT%"
echo Last word: "%PREV%"

endlocal
exit /B

这种方法returns删除了最后一个单词的名字以及名字的最后一个单词。


另一种解决方案是有时所谓的代码注入技术,它需要 delayed variable expansion 并且很难理解:

setlocal EnableDelayedExpansion
echo Old name: "%FOLDER%"
set "RESULT=%FOLDER: =" & set "RESULT=!RESULT!!ITEM!" & set "ITEM= %"
echo New name: "%RESULT%"
echo Last word: "%ITEM:* =%"
endlocal

请注意,当输入字符串包含 !^"(但后者无论如何不能出现在文件或目录名称中)时,这将失败。


另一种方法是用 \ 替换空格,然后(误)使用 ~-modifiers,这是可行的,因为纯文件或目录名称不能包含 \它自己的:

echo Old name: "%FOLDER%"
rem // Precede `\` to make pseudo-path relative to root, then replace each ` ` by `\`:
for %%I in ("\%FOLDER: =\%") do (
    rem // Let `for` meta-variable expansion do the job:
    set "RESULT=%%~pI"
    set "LAST=%%~nxI"
)
rem // Remove leading and trailing `\`; then revert replacement of ` ` by `\`:
set "RESULT=%RESULT:~1,-1%"
echo New name: "%RESULT:\= %"
echo Last word: "%LAST%"

这种方法甚至不需要delayed expansion