当字符串与分隔符具有相同的字符时,如何仅处理特定的分隔符

时间:2018-05-03 20:56:30

标签: batch-file

当字符串与分隔符具有相同字符时,如何仅处理特定分隔符?

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

IT在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 :(得分:3)

更改文件

data1.txt:

/** @var \Doctrine\ORM\EntityManager */
private $entityManager;

public function setUp()
{
    $client = static::createClient();
    $this->entityManager = $client
        ->getContainer()
        ->get('doctrine')
        ->getManager();
}

data2.txt:

a.pnh_1
bb.pop_22
c c.oiu_333

此批次

_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

答案 1 :(得分:1)

使用标准for循环在每个_符号处拆分每个行字符串怎么样?当您将字符串括在""之间并将每个_替换为" "时,您会得到""之间的部分字符串;例如,e_e.pop_555变为"e" "e.pop" "555"。因此,您可以遍历它们并在新变量中重新组合它们并关闭最后一项,从而获得e_e.pop555。这比gotocall快,因为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

这是一种完全不同的方法,基于我在another answer中使用的一个很好的黑客:

@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

不允许使用以下字符:!^"