【问题标题】:batch for loop, csv parsing and issue with proper output to the file批处理循环,csv 解析和正确输出到文件的问题
【发布时间】:2013-03-20 17:37:47
【问题描述】:

让我描述一下我的问题。 我有一个从 excel 导出的包含大量数据的 csv 文件。 该文件在第一行有标题,在第二行有列标题。 我只需要从该文件中提取两列(第 2 列和第 3 列), 将它们放在 1 列并将输出发送到另一个文件。

例子:

Title
colA , colB , colC , colD ,...
abc  , def  , ghi  , jkl  ,...
abc  , def  , ghi  , jkl  ,...
abc  , def  , ghi  , jkl  ,...
abc  , def  , ghi  , jkl  ,...

问题是,csv 解析器在遇到行时失败 包含带有 - ( ) @ 字符的字符串。 (循环将它们视为我认为的分隔符,因此每次都会给我一个超出范围的错误)。

这是我已经拥有的。

@Echo off & setlocal EnableExtensions
setLocal EnableDelayedExpansion

REM creating and clearing files
copy /y NUL C:\list1.csv >NUL
copy /y NUL C:\list1_tmp.csv >NUL
copy /y NUL C:\exportedColumns.csv >NUL
copy /y NUL C:\Result.txt >NUL

set Result=C:\Result.txt
set Source=C:\sourcelist.csv
set list1=C:\list1.csv
set list1_tmp=C:\list1_tmp.csv
set expCol=C:\exportedColumns.csv

REM skip 1st two lines from source file and put to output file list1
for /f "skip=2 delims=*" %%a in (%Source%) do (echo %%a >>%list1%)

REM shorten each line to 500 chars and put it to new file
for /f "tokens=* delims=" %%a in ("%list1%") do (
set s=%%a
set s=%s:~0,500% 
echo.%s% >> "%list1_tmp%"
)
REM ^^^^^^^^^^^ this is not working. It puts only 1 space to the output file

rem Parsing the csv file
rem Process the file:
call :ProcessFile < %list1_tmp%
exit /B

:ProcessFile
set /P line=
:nextLine
    set line=:EOF
    set /P line=
    if "!line!" == ":EOF" goto :EOF
    set i=0
    for %%e in (%line%) do (
        set /A i+=1
        for %%i in (!i!) do (
        if %%i==1 echo %%~e >> %expCol%
        if %%i==2 echo %%~e >> %expCol%
    )
    if %%i==3 goto nextLine
    REM I don't want it to process all the columns
    )
goto nextLine

我想请你看看这个并帮助我将 2 列合二为一 并将输出放到 1 个文件中。

非常感谢。

【问题讨论】:

  • 对于在你想要之前被评估的回声,将其更改为&gt;&gt;"%list1_tmp%" echo.!s! 以延迟%s% 的扩展是否有帮助? (我只是重新排序了命令重定向,以防止将尾随空格回显到 %list1_tmp%,但这不是重要的部分。)

标签: csv for-loop batch-file


【解决方案1】:

这个怎么样?

for /f "skip=2 tokens=2,3 delims=, " %i in (input.csv) do echo %i%j >> output.csv

编辑:

要将 / 替换为换行符,您可以试试这个:

@echo off

for /f "skip=2 tokens=2,3 delims=, " %%i in (test.csv) do call :replace %%i%%%j
goto :eof

:replace
set string=%*
For /f "tokens=1,* delims=/" %%a in ('echo %string%') Do (
echo.%%a
If not "%%b"=="" call :replace %%b)

对于输入:

title
colA , colB , colC , colD ,...
abc  , def  , g\hi  , jkl  ,...

上面会输出:

defg
hi

【讨论】:

  • 返回的是 ij 出乎意料。
  • 好的,我刚刚将 %i 更改为 %%i 并将 %i%j 更改为 %%i 并且它起作用了。现在我需要对其进行排序并删除重复项。我可能会在移除时使用你的帮助,尽管我会先挖掘这个板 :)
  • 好的。现在已对其进行排序和重复数据删除。知道如何将斜杠替换为输入符号吗? ^p?
  • @user2192002 查看编辑!但您可能仍需要对特定数据进行一些调整
  • 很抱歉再次打扰您。我有 1 个文件,其中有一列中的名称列表。我已经设法摆脱了每一行的所有引号。但是我无法获得将 / ( ) 字符更改为 ^p (输入,换行)并将输出放入新文件的正确代码。你能帮帮我吗?
【解决方案2】:

您提到的一个问题是在for %%e in (%line%) do ... 行中,当%line% 包含诸如( 之类的特殊字符时,自然会弄乱解释器。

您可以通过使用字符串替换来避免这种情况,以便在每列周围加上引号。例如(我跳过了你的一些代码,只关注有问题的部分):

:ProcessFile
set /P line=
:nextLine
    for %%e in ("%line:,=" "%") do (
        echo %%~e
    )
goto nextLine

注意这部分:"%line:,=" "%"。即用" " 替换所有逗号,并在行首和行尾添加"

因此,如果我们正在处理的特定行如下所示:

abc, def (foo), ghi

for 将扩展为:

for %%e in ("abc" "def (foo)" "ghi") do ...

所有内容都很好地包含在引号中,因此( 不会干扰。当然,如果您在特定列中有引号,那会干扰...

在我使用%%e 的下一行,我将其设为%%~e 以去除引号。

【讨论】:

  • " "此时出乎意料
【解决方案3】:

今天早上我一直在尝试将 CSV 文件作为 ADODB 记录集访问。我的代码可能对你有用。实际上,脚本会遍历当前目录中的每个.csv 文件,并为每一行显示column = value

JScript 应该很容易修改以根据需要组合列。由于这是一个批处理/JScript 混合,您可以选择是否要创建 Scripting.FileSystemObject 对象或只是重定向 cscript 行的输出以生成新的 .csv 文件。

这是csv.bat 的代码。 *耸耸肩* 这并不是最终的答案,而是建议的替代路径。

@if (@a==@b) @end /*

:: batch portion

@echo off
setlocal

:: force 32-bit environment for ODBC drivers
if exist "%windir%\syswow64\cmd.exe" (set "cmd=%windir%\syswow64\cmd.exe") else set "cmd=cmd.exe"

for /r %%I in (*.csv) do (
    echo Processing %%~nxI:
    echo;
    %cmd% /c cscript /nologo /e:jscript "%~f0" "%%~dpI" "%%~nxI"
    echo;
)

goto :EOF

:: JScript portion */
var conn = new ActiveXObject("ADODB.Connection");
var rs = new ActiveXObject("ADODB.Recordset");

var dsn = "Driver={Microsoft Text Driver (*.txt; *.csv)};"
    + "Dbq=" + WSH.Arguments(0) + ";"
    + "Extensions=asc,csv,tab,txt;";

try { conn.Open(dsn); }
catch(e) {

    // If the Microsoft Text Driver didn't work,
    // try the MS Jet 4.0 provider instead.

    var dsn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
    + WSH.Arguments(0)
    + ";Extended Properties=\"text;HDR=Yes;FMT=Delimited\";";

    try { conn.Open(dsn); }
    catch(e) {

        // If that didn't work either, then give up.

        WSH.Echo("Unable to create ADODB connection.");
        WSH.Quit(1);
    }
}

rs.Open("SELECT * from " + WSH.Arguments(1), conn, 2, 4);

while (!rs.EOF) {
    for (var i=0; i<rs.Fields.Count; i++) {
        WSH.Echo(rs.Fields(i).Name + ' = ' + rs.Fields(i));
    }
    rs.MoveNext;
}

rs.Close();
conn.Close();

【讨论】:

    猜你喜欢
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    相关资源
    最近更新 更多