使用批处理文件解析csv文件中的行

时间:2017-03-20 16:33:18

标签: csv parsing batch-file command-line cmd

更新

我想解析一个csv文件并使用这些信息。在打开文件之前,我不知道行中元素的数量。我不知道行数。我想首先解析标题,然后我可以知道用于解析行的标记。我希望以矩阵形式得到结果,因此很容易使用。

我还想创建一个csv,以便稍后导出我的结果。

这是我要解析的csv的一个例子(限于3行,10列)。

"","rim_no","account_no","observation_date","observation_month","start_date","maturity_date","days_past_due","rate","spread"
"1",2517,1000008332,20160831,201608,NA,NA,0,17,0
"2",2517,1000008332,20160930,201609,NA,NA,0,17,0

我事先并不知道行数和列数。我也不知道列的顺序。让我说我想用帐号,观察月和速率,首先我想解析标题以获得3,5,9的位置,所以我可以在解析其他行时使用它们作为标记来获取信息

我设法做了一半我想要的东西,这是我写的代码(现在,我只是读写,后来我只保留我感兴趣的变量并进行额外的计算):

@ECHO off
SETLOCAL EnableDelayedExpansion

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::Adress of the input and output files

GOTO InFile

:FalseIN 
ECHO You need to enter a valid location for the source file. 
GOTO InFile

:InFile
ECHO Please enter the location of your file in like C:\XXXX\YYYY\ZZZZ\example.csv
SET _fileIn
SET /P _fileIn=Type input: %=%
IF NOT EXIST "%_fileIn%" GOTO FalseIn
ECHO The selected input file to work with is %_fileIn%

:OutFile
ECHO Please enter the name of your output like C:\XXXX\YYYY\ZZZZ\output.csv
SET _fileOut
SET /P _fileOut=Type input: %=%
IF NOT EXIST "%_fileOut%" set "_fileOut=C:\XXXX\YYYY\ZZZZ\Output.csv"
ECHO.>"%_fileOut%"
ECHO The selected output file to work with is %_fileOut%

ECHO stop 1   
@PAUSE

SET _ligne=0
SET _colonne=0

CALL :ParseHeader "%_fileIn%"

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GOTO :eof
::Parse input file header, first element
:ParseHeader
SET /a _countParse+=1
SET _list=%1
SET _list=%_list:"=%
FOR /F "tokens=1* delims=, " %%a IN ('TYPE "%_list%"') DO (
    set _matrice[%_ligne%][%_colonne%]=%%a
    set /a _colonne+=1
    if not "%%b"=="" call :ParseHeaderBis "%%b"
)

GOTO :eof

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GOTO :eof  
::Parse input file header, from second element onward
:ParseHeaderBis
SET /a _countParseBis+=1
SET _list=%1
SET _list=%_list:"=%
FOR /F "tokens=1* delims=, " %%a IN ("%_list%") DO (
    set _matrice[%_ligne%][%_colonne%]=%%a
    if not "%%b"=="" set /a _colonne+=1
    if not "%%b"=="" if %_ligne% equ 0 call :ParseHeaderBis "%%b"
    if "%%b"=="" set /a _ligne+=1
)

@PAUSE

IF %_ligne% gtr 0 GOTO :EchoHeader 

GOTO :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:EchoHeader
FOR /L %%H IN (0,1,%_colonne%) DO (
    echo|set /p=!_matrice[0][%%H]!>>%_fileOut%
    if not %%H equ %_colonne% echo|set /p=,>>%_fileOut%
    if %%H equ %_colonne% echo.>>%_fileOut%
)

@PAUSE

CALL :Next 

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GOTO :eof
::Parse input file data, from second row onward, get lines
:Next
SET /a _countNext+=1
SET /a _ligneAct=%_ligne%
SET _colonne=0
FOR /F "skip=%_ligne% tokens=* delims=" %%a IN ('type "%_fileIn%"') DO (
    if not "%%a"=="" call :NextBis "%%a"
    if "%%a"=="" goto :eof
)

GOTO :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GOTO :eof
::Parse the lines from the input file
:NextBis
SET /a _countNextBis+=1
SET _list=%1
SET _list=%_list:"=%
FOR /F "tokens=1* delims=, " %%a IN ("%_list%") DO (
    set _matrice[%_ligne%][%_colonne%]=%%a
    if not "%%b"==""  set /a _colonne+=1
    if not "%%b"==""  if %_ligne% equ %_ligneAct%  call :NextBis "%%b"
    if "%%b"==""  set /a _ligne+=1 
)

IF %_ligne% gtr %_ligneAct% GOTO :EchoData 

GOTO :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:EchoData
SET _var=""
FOR /L %%H IN (0,1,%_colonne%) DO (
    if %%H equ 0 set _var=!_matrice[%_ligneAct%][%%H]!
    set _help=!_var!
    if %%H gtr 0 set _var=!_help!, !_matrice[%_ligneAct%][%%H]!
    echo !_var!
    if %%H equ %_colonne% echo !_var!>>%_fileOut%
    ::echo|set /p=!_matrice[%_ligneAct%][%%H]!>>%_fileOut%
    ::if not %%H equ %_colonne% echo|set /p=,>>%_fileOut%
    ::if %%H equ %_colonne% echo.>>%_fileOut%
)

@PAUSE

CALL :Next

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:eof 
@PAUSE

但我仍有两个问题:

  • 我最初以与我相同的方式导出所有内容 :EchoHeader,但这很慢,所以我决定先连接 元素和外包整行(参见:EchoData)。事情是 我得到一个错误,无法导出;我不明白为什么。当我回声 !_var!并取消注释我的for循环的最后三行 :EchoData,我可以看到_var是我想要的,但在评论时,它 只是虫子;
  • 即使没有任何内容,下一个/下一个双循环也在运行 离开阅读,我想我的转到:eof会避免这个,但我 显然错过了什么,我现在找不到什么。

非常感谢任何帮助。

ps:我认为我的代码不是最优的,任何改善运行时间的想法也值得赞赏:)

1 个答案:

答案 0 :(得分:0)

子程序/函数是构造代码的一件好事,但是:

  • 你要注意程序不会无意中流入它们。在前面插入goto :eof
  • 在子/函数末尾的
  • 还插入goto :eof以将控件返回给调用者。
  • 除非您知道自己在做什么,否则不要使用标签内部的代码块。请改用REMs
  • 只需使用set /P "header="<infile.txt
  • 即可阅读文件的第一行
  • 你似乎递归地用不同的参数类型调用ParseHeader,一次是文件名,然后是标题的其余部分(%% b)
  • 在暂停之前看到您的二维_matrice问题set _matrice的中间结果,看看里面是什么。

这不是一个真正的答案,而是要发表意见。

  • 您可以将vbs / PowerShell函数与文件选择器一起使用,而不是容易出错的手动用户输入。
  • 为了帮助其他人,你应该展示一个你想要检查的典型csv以及你期望的结果(例如对齐列)