帮助编写批处理脚本来解析CSV文件并输出文本文件

时间:2011-06-24 16:04:39

标签: windows text csv batch-file record

我正在努力编写一个可以读取CSV文件的批处理脚本,如下面的

Name:, City:, Country:
Mark, London, UK
Ben, Paris, France
Tom, Athens, Greece

CSV文件中会有一个标题行。它应输出到文本文件,如下所示:

Name:Mark
City:London
Country:UK

Name:Ben
City:Paris
Country:France

Name:Tom
City:Athens
Country:Greece

上述输出中的字段分隔符(:)应该在标题行本身中提供。所以我需要做的就是连接字段标题及其值。

此CSV文件中的列数未固定,因此脚本不应限制为3个令牌。请帮助!

4 个答案:

答案 0 :(得分:7)

@ECHO OFF
IF "%~1"=="" GOTO :EOF
SET "filename=%~1"
SET fcount=0
SET linenum=0
FOR /F "usebackq tokens=1-10 delims=," %%a IN ("%filename%") DO ^
CALL :process "%%a" "%%b" "%%c" "%%d" "%%e" "%%f" "%%g" "%%h" "%%i" "%%j"
GOTO :EOF

:trim
SET "tmp=%~1"
:trimlead
IF NOT "%tmp:~0,1%"==" " GOTO :EOF
SET "tmp=%tmp:~1%"
GOTO trimlead

:process
SET /A linenum+=1
IF "%linenum%"=="1" GOTO picknames

SET ind=0
:display
IF "%fcount%"=="%ind%" (ECHO.&GOTO :EOF)
SET /A ind+=1
CALL :trim %1
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO !f%ind%!!tmp!
ENDLOCAL
SHIFT
GOTO display

:picknames
IF %1=="" GOTO :EOF
CALL :trim %1
SET /a fcount+=1
SET "f%fcount%=%tmp%"
SHIFT
GOTO picknames

此批次scipt:

  • 接受一个参数,即要处理的文件的名称;

  • 不验证标头令牌末尾是否存在:,当显示这些值时,它们会立即放在相应的标头令牌之后;

  • 修剪所有前导空格(但不包括尾随空格);

  • 认为第一行是标题行,它还定义了后续行中要处理的标记数;

  • 最多支持10个令牌,以粗体斜体突出显示的两个区域负责(因此当您需要更改最大数量时,请修改这两个区域:如果增加数量,则必须展开{ {1}}列表,同样,如果减少数量,则缩小列表。)

答案 1 :(得分:7)

我知道这是一个老问题,但这类问题是我最喜欢的问题,所以这是我的答案:

@echo off
setlocal EnableDelayedExpansion

rem Create heading array:
set /P headingRow=< %1
set i=0
for %%h in (%headingRow%) do (
    set /A i+=1
    set heading[!i!]=%%~h
)

rem Process the file:
call :ProcessFile < %1
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 echo !heading[%%i]!%%~e
    )
goto nextLine
exit /B

该程序对字段数没有任何限制。此版本要求在引号中包含可能包含空格或其他批处理分隔符的元素,但此限制可能很容易修复。

答案 2 :(得分:2)

Python使这一点变得如此简单,应由政府监管。

from csv import DictReader

with open('file', 'rb') as file:
    reader = DictReader(file)

    for line in reader:
        for field in reader.fieldnames:
            print '{0}{1}'.format(field.strip(), line[field].strip())

         print '\n'

编辑:我猜你需要Windows命令shell的原生内容。哦,好吧。

答案 3 :(得分:0)

  Function CSVArray(CSVFile)

  Dim comma, quote
  comma = ","
  quote = Chr(34)

  Dim charPos, charVal

  Dim cellPos, colMax, colNum
  colMax  = -1

  Dim cellArray(), cellComplete, cellQuoted, csvRecord

  Dim inCsvSys, inCsv, inRow(), rowCount
  rowCount     = -1
  Set inCsvSys = CreateObject("Scripting.FileSystemObject")
  Set inCsv    = inCsvSys.OpenTextFile(CSVFile,"1",True)
  Do While Not inCsv.AtEndOfStream
    rowCount = rowCount + 1
    Redim Preserve inRow(rowCount)
    inRow(rowCount) = inCsv.ReadLine
  Loop
  inCsv.Close

  For r = 0 to rowCount

    csvRecord = inRow(r)
    colNum = -1
    charPos = 0
    cellComplete = True

    Do While charPos < Len(csvRecord)

      If (cellComplete = True) Then
        colNum       = colNum + 1
        cellPos      = 0
        cellQuoted   = False
        cellComplete = False
        If colNum > colMax Then
          colMax = colNum
          Redim Preserve cellArray(rowCount,colMax)
        End If              
      End If

      charPos = charPos + 1
      cellPos = cellPos + 1
      charVal = Mid(csvRecord, charPos, 1)
      If (charVal = quote) Then
        If (cellPos = 1) Then
          cellQuoted = True
          charVal    = ""
        Else
          Select Case Mid(csvRecord, charPos+1, 1)
          Case quote
            charPos = charPos + 1
          Case comma
            charPos = charPos + 1
            cellComplete = True
          End Select
        End If
      ElseIf (charVal = comma) And (cellQuoted = False) Then
        cellComplete = True
      End If
      If (cellComplete = False) Then
        cellArray(r,colNum) = cellArray(r,colNum)&charVal
      End If

    Loop

  Next
  CSVArray = cellArray
End Function

Dim StdOut
Set StdOut = WScript.StdOut
Dim csv

If Wscript.Arguments.Count = 0 Then
    Wscript.StdOut.WriteLine "Invalid Arguments"
Else
    csv = CSVArray(Wscript.Arguments(0))
End If


For r = 1 to UBound(csv,1)
  For c = 0 to UBound(csv,2)
    Wscript.StdOut.WriteLine csv(0,c) & csv(r,c)
  Next
Next