2

I have a folder with many delimiters "_": text4_text5_text6_text7_2000-01-02

I need to create from it 2 vars. 1st one is everything from foldername until last delimieter. 2nd one is after last delimiter:

  • %name% = text4_text5_text6_text7
  • %date% = 2000-01-02

For date I have this code:

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

But I can't figure out hot to take into %NAME% everything else before %DATE%.

I will appreciate any tip.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
MikeZetPL
  • 97
  • 5
  • 1
    is date always the last item? In other words the `_` before date is the last `_` in the name? – Gerhard Feb 15 '22 at 08:34
  • 2
    If the date is always 10 characters, you can use substring (`%DIR:~-10%` and `%DIR:~0,-11%`): https://stackoverflow.com/questions/636381/what-is-the-best-way-to-do-a-substring-in-a-batch-file – VLL Feb 15 '22 at 08:52
  • Date is always last delimiter, but sometimes it shorten, than in this example. For sure date its after last delimiter. I'm figuring out how to get as variable all folder name besides everything after last delimiter. – MikeZetPL Feb 15 '22 at 08:55
  • 1
    *N. B.:* `set` is sensitive to spaces, so `SET DIR = …` sets a variable named `DIR` + _space_ to a value like _space_ + `…`; best is to use the quoted syntax like `set "DIR=…"` to protect special characters and also to avoid unwanted trailing spaces… – aschipfl Feb 15 '22 at 09:59

6 Answers6

3

If the format is as you mentioned, with the last _ always containing the date after:

@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%

Here %mydate% is the variable containing the date and %restofline% contains the rest.

Gerhard
  • 22,678
  • 7
  • 27
  • 43
2

I think this is the simplest way to do this:

@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%"

This method works via a simple substring replacement that produces several commands. You may appreciate it by removing the @echo off line and reviewing the executed code in the screen. For a further explanation on this method, see this thread.


If you want a more standard method, then this one is simple:

@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%"
Aacini
  • 65,180
  • 12
  • 72
  • 108
0

You can put all values into array of string. Last value of array must be %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
Daemon-5
  • 241
  • 1
  • 6
0

Here is a method that applies the sometimes so-called code injection technique:

@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

The related console output is going to be the following:

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

To find out how it works change @echo off to @echo on and check the console output. This method is based on sub-string substitution, and it requires delayed variable expansion.

Regard, that this approach will fail with a string that contains !, ^ and ".

Notice, that multiple consecutive separators become collapsed into one, so a string like abc__def__01 would be split into abc_def and 01. To avoid that and thus retain the separators, change the core code to this:

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=%"

For more information about this method refer to split string into substrings based on delimiter [DosTips].

aschipfl
  • 33,626
  • 12
  • 54
  • 99
0

Here is an approach based on your code using a standard for-loop:

@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

Regard, that this approach will fail with a string that contains wildcards like ?, * and <, >; moreover, !, ^ and " must not occur in the string.

To at least avoid troubles with !, ^ and " in the string, use this more robust but more complex code instead:

@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
aschipfl
  • 33,626
  • 12
  • 54
  • 99
0

One way to do it in a cmd batch-file on windows would be to use a regex in PowerShell. If you are on a supported Windows system, PowerShell is installed.

Note that I changed the result variable name DATE to THE_DATE. DATE is an automatic variable in cmd and should not be used separately.

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
lit
  • 14,456
  • 10
  • 65
  • 119