批处理循环,CSV解析和正确输出到文件的问题

3
让我描述一下我的问题。 我有一个从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

我希望你能看一下这个,帮我把两列合并到一个文件中并输出结果。非常感谢。

对于在您想要之前被评估的回显,将其更改为>>"%list1_tmp%" echo.!s!有助于延迟%s%的扩展吗?(我只是重新排列了命令重定向,以防止将尾随空格回显到%list1_tmp%中,但这不是重点。) - rojo
3个回答

2
这个怎么样?
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 是意外的。 - skazichris
好的,我刚刚将%i更改为%%i并将echo %i%j更改为%%i,它可以工作了。现在我需要对其进行排序并删除重复项。我可能需要你的帮助来进行删除,尽管我会先搜索一下这个论坛 :) - skazichris
好的。现在已经排序并去重了。有什么想法如何将斜杠替换为换行符?^p? - skazichris
@user2192002 看一下修改!但是你可能仍然需要针对你的特定数据进行一些微调。 - Sean Landsman
抱歉再次打扰您。我有一个文件,其中包含一个列出的名称列表。我已经成功地从每行中删除了所有引号。但是我无法得到正确的代码来将/()字符更改为^p(换行符,新行),并将输出放入新文件中。您能帮我吗? - skazichris
显示剩余5条评论

0
你提到的问题之一在于这行代码: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 以去除引号。


此时出现了意料之外的“ ”。 - skazichris

0

今天早上我刚好在尝试使用ADODB记录集访问CSV文件。我的代码可能对你有用。目前,这个脚本会循环遍历当前目录中的每个.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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接