Как обрабатывать только определенный разделитель, если строка содержит одинаковые символы с разделителем - PullRequest
0 голосов

Как обрабатывать только определенный разделитель, если строка содержит одинаковые символы с разделителем?.

Sample.bat

@echo off & Setlocal EnableDelayedExpansion

:: Load  Variable From data*.txt

set /a Line=0
for /f "delims=" %%a in (data*.txt) do (
    set /A Line+=1
    for /f "tokens=1,2 delims=_" %%b in ("%%a") do (
        set "data_in!Line!=%%b" & set "data_out!Line!=%%c"
    )
)

set data

pause

data1.txt:

a.pnh_111
bb.pop_222
c c.oiu_333

data2.txt:

_dd.pnh_444
e_e.pop_555
ff_.oiu_666

Вывод из data1.txt

data_in1=a.pnh
data_in2=bb.pop
data_in3=c c.oiu

data_out1=111
data_out2=222
data_out3=333

Он отлично работал на data1.txt

Но вывод из data2.txt НЕ РАБОТАЕТ, КАК ОЖИДАЕТСЯ, потому что он имеет 2 символа "_"

Вывод из data2.txt того, что я хочу:

data_in1=_dd.pnh
data_in2=e_e.pop
data_in3=ff_.oiu

data_out1=444
data_out2=555
data_out3=666

когда я заменил разделитель "_" на "(разделитель)" для всех данных * .txt, например:

data1.txt:

a_a.pnh(separator)111
abb.pop(separator)222
ccc.oiu(separator)333

и измените разделитель на:

/f "tokens=1,2 delims=(separator)" %%b in ("%%a") do (

Конечно, это не работает.

Примечания: Данные * .txt записаны другой программой. В настоящее время, используя символ «_» в качестве разделителя, но я могу изменить его на другой символ (я не могу предсказать, какой вывод будет записан в data.txt. Может иметь такой же символ, что и разделитель, который я использую)

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Как насчет использования стандартного цикла 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

Следующие символы не допускаются для этого: !, ^ и ".

0 голосов
/ 04 мая 2018

с измененными файлами

data1.txt:

a.pnh_1
bb.pop_22
c c.oiu_333

data2.txt:

_dd.pnh_4444
e_e.pop_55555
ff_.oiu_666666

Эта партия

:: Q:\Test\2018\05\03\SO_50163726_2.cmd
@echo off & Setlocal 
:: Load  Variable From data*.txt
set Cnt=0
for %%A in (data*.txt) do for /f "delims=" %%B in (%%A) DO Call :ProcLine %%B
set data
pause
goto :Eof

:ProcLine
set /A Cnt+=1
set "Line=%~1"
Call :GetNum %Line:_= %
Rem Echo Num=%Num%
Call Set "Line=%%Line:_%Num%=%%"
set "data_in%Cnt%=%Line%" 
set "data_out%Cnt%=%Num%"
Goto :Eof

:GetNum
if "%~2" neq "" (shift&goto :GetNum)
Set Num=%1
Goto :Eof

выдаст этот вывод:

data_in1=a.pnh
data_in2=bb.pop
data_in3=c c.oiu
data_in4=_dd.pnh
data_in5=e_e.pop
data_in6=ff_.oiu
data_out1=1
data_out2=22
data_out3=333
data_out4=4444
data_out5=55555
data_out6=666666
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...