让我来描述我的问题。 我有一个从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个文件中。
我非常感激。
答案 0 :(得分: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
答案 1 :(得分: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
以便删除引号。
答案 2 :(得分: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();