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

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

我将不胜感激。

4

3 回答 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
于 2013-03-20T17:59:47.547 回答
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是为了去掉引号。

于 2013-03-20T18:06:58.690 回答
0

碰巧我今天早上一直在尝试将 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();
于 2013-03-20T18:59:03.207 回答