当字符串与分隔符具有相同字符时,如何仅处理特定分隔符?
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。可能它与我使用的分隔符具有相同的字符)
答案 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.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
这是一种完全不同的方法,基于我在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
不允许使用以下字符:!
,^
和"
。