Как насчет использования стандартного цикла for
для разделения каждой строки строки на каждый символ _
? Когда вы заключаете строку между ""
и заменяете каждые _
на " "
, вы получаете частичные строки, заключенные между ""
; так, например, e_e.pop_555
становится "e" "e.pop" "555"
. Следовательно, вы можете проходить через них, собирать их в новую переменную и отклонять последний элемент, получая, таким образом, e_e.pop
и 555
Это быстрее, чем goto
или call
, поскольку циклы for
кэшируются в памяти.
Вот пример кода:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~1" & rem // (input file; use first command line argument)
rem // Initialise counter:
set /A "COUNT=0"
rem // Read input file line by line, ignoring empty lines:
for /F usebackq^ delims^=^ eol^= %%L in ("%_FILE%") do (
rem // Store current line:
set "LINE=%%L"
rem // Increment counter:
set /A "COUNT+=1"
rem // Initialise interim variables:
set "COLL=" & set "ITEM="
rem // Toggle delayed expansion to avoid loss of `!`:
setlocal EnableDelayedExpansion
rem /* Split line at every `_` and loop through items
rem (`?`, `*`, `<`, `>` and `"` must not occur): */
for %%I in ("!LINE:_=" "!") do (
rem /* Append previous item to variable; use `for /F`
rem to transport value beyond `endlocal` barrier: */
for /F "delims=" %%K in ("COLL=!COLL!_!ITEM!") do (
endlocal
set "%%K"
)
rem // Store current item for next iteration, remove `""`:
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
)
rem /* Store appended string to `data_in` variable, then
rem store last item to `data_out` variable; use `for /F`
rem to transport value beyond `endlocal` barrier: */
for /F "delims=" %%I in ("data_in!COUNT!=!COLL:~2!") do (
for /F "delims=" %%J in ("data_out!COUNT!=!ITEM!") do (
endlocal
set "%%I" & set "%%J"
)
)
)
rem // Return stored data:
set data_
endlocal
exit /B
Этот подход не теряет восклицательные знаки (!
) во входных строках и не вызывает других проблем с ними. Однако следующие символы не допускаются: ?
, *
, <
, >
и "
.
Поскольку в файлах данных нет восклицательных знаков (!
), сценарий можно упростить до следующего:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~1" & rem // (input file; use first command line argument)
setlocal EnableDelayedExpansion
rem // Initialise counter:
set /A "COUNT=0"
rem // Read input file line by line, ignoring empty lines:
for /F usebackq^ delims^=^ eol^= %%L in ("!_FILE!") do (
rem // Store current line:
set "LINE=%%L"
rem // Increment counter:
set /A "COUNT+=1"
rem // Initialise interim variables:
set "COLL=" & set "ITEM="
rem /* Split line at every `_` and loop through items
rem (`?`, `*`, `<`, `>` and `"` must not occur): */
for %%I in ("!LINE:_=" "!") do (
rem // Append previous item to variable:
set "COLL=!COLL!_!ITEM!"
rem // Store current item for next iteration, remove `""`:
set "ITEM=%%~I"
)
rem /* Store appended string to `data_in` variable, then
rem store last item to `data_out` variable: */
set "data_in!COUNT!=!COLL:~2!" & set "data_out!COUNT!=!ITEM!"
)
rem // Return stored data:
set data_
endlocal
endlocal
exit /B
Это совершенно другой подход, основанный на хорошем хаке, который я уже использовал в другой ответ :
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~1" & rem // (input file; use first command line argument)
setlocal EnableDelayedExpansion
rem // Initialise counter:
set /A "COUNT=0"
rem // Read input file line by line, ignoring empty lines:
for /F usebackq^ delims^=^ eol^= %%L in ("!_FILE!") do (
rem // Increment counter:
set /A "COUNT+=1"
rem /* Split current line at last `_`, then store the string before to
rem `data_in` variable and the string after to `data_out` variable: */
call :GET_LAST_ITEM data_out!COUNT! data_in!COUNT! "%%L"
)
rem // Return stored data:
set data_
endlocal
endlocal
exit /B
:GET_LAST_ITEM rtn_last rtn_without_last val_string
::This function splits off the last `_`-separated item of a string.
::Note that `!`, `^` and `"` must not occur within the given string.
::PARAMETERS:
:: rtn_last variable to receive the last item
:: rtn_without_last variable to receive the remaining string
:: val_string original string
setlocal EnableDelayedExpansion
set "STR=_%~3"
set "PRE=" & set "END=%STR:_=" & set "PRE=!PRE!_!END!" & set "END=%"
endlocal & set "%~1=%END%" & set "%~2=%PRE:~2%"
exit /B
Следующие символы не допускаются для этого: !
, ^
и "
.