【问题标题】:Reading a file with a batch with n tokens including empty ones读取包含 n 个标记(包括空标记)的批处理文件
【发布时间】:2014-02-04 11:52:22
【问题描述】:
我想编写一个读取文件每一行的批处理脚本。听起来很简单,但问题是并非每一行都有相同数量的令牌。接下来是每个标记都使用分隔符彼此分隔,我不想在输出中包含该分隔符。
以下是文件示例:
string1|string2|string3|string4
string1|||string4
当我阅读该文件时,每个标记都必须在正确的位置。我的意思是当我阅读第二行时,输出必须是:
string1 空字符串 4
感谢帮助
【问题讨论】:
标签:
batch-file
for-loop
token
【解决方案1】:
gawk for Windows 可以完成这项工作:
awk -F"|" "{for (i=1;i<=NF;i++) $i=$i?$i:\"empty\"};7" file.in>file.out
【解决方案2】:
@ECHO OFF
SETLOCAL
(
FOR /f "delims=" %%a IN (q21551753.txt) DO (
SET line=%%a
SETLOCAL ENABLEDELAYEDEXPANSION
SET line=!line:^|= ^|!
ECHO(!line!
endlocal
)
)>tempfile.txt
SET "spaces= "
FOR /f "tokens=1-7delims=|" %%a IN (tempfile.txt) DO (
SET "$a=%%a%spaces%"
SET "$b=%%b%spaces%"
SET "$c=%%c%spaces%"
SET "$d=%%d%spaces%"
SET "$e=%%e%spaces%"
SET "$f=%%f%spaces%"
SET "$g=%%g%spaces%"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO(!$a:~0,8!!$b:~0,9!!$c:~0,8!!$d:~0,8!!$e:~0,9!!$f:~0,5!!$g:~0,6!
endlocal
)
GOTO :EOF
我使用了一个名为 q21551753.txt 的文件进行测试。
string1|string2|string3|string4
string1|||string4
|string2||string4|string5|string6
%one%|!2!||"three"|^four^|string6
回复:
string1 string2 string3 string4
string1 string4
string2 string4 string5 strin
%one% !2! "three" ^four^ strin
请注意,列宽是在ECHO(!$a... 语句中定义的——您可以选择每列的数量和宽度。请注意,spaces 设置为一堆空格。
tempfile.txt 已创建。是否删除它,它是在哪里创建的,以及你如何称呼它,都取决于你。
【解决方案3】:
以下假设数据不包含!,并且没有行以; 开头。这些限制可以通过更多的代码来消除。
关键技巧是使用变量扩展搜索和替换将str1|str2|str3|str4 转换为"str1"|"str2"|"str3"|"str4"。然后第二个 FOR /F 可以安全地解析标记,即使值丢失。您需要的值位于 %%~A、%%~B、%%~C 和 %%~D 中。 I ECHO 这行只是为了展示每个token的价值。
@echo off
setlocal enableDelayedExpansion
for /f "delims=" %%L in (test.txt) do (
set "ln=%%L"
set "ln="!ln:^|="|"!""
for /f "tokens=1-4 delims=|" %%A in ("!ln!") do (
echo A=%%~A B=%%~B C=%%~C D=%%~D
)
)
【解决方案4】:
感谢您的回答。
但我发现我还有另一个问题。令牌的数量并不总是相同的,并且通常在一行中大约有 20-40 个令牌。
我用子程序创建了一个解决方案:
@echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (Book1.csv) DO (
set "work=%%a"
for /l %%i in (1,1,2) do set "work=!work:||=|NULL|!"
set "line=!work!"
call :processToken
)
goto eof
:processToken
for /F "tokens=1* delims=|" %%x in ("!line!") do (
echo %%x
set line=%%y
)
if not "!line!" == "" goto :processToken
goto :eof
:eof