我正在努力编写一个可以读取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个标记。 请帮助!
@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个令牌,而用粗体斜体突出显示的两个区域是负责的(所以当你需要改变最大数量时,修改两个区域:如果增加数量,则必须展开"%%a" "%%b" "%%c" …
列表,同样,如果您减少数字,然后缩小列表)。
我知道这是一个古老的问题,但这类问题是我最喜欢的问题,所以这里是我的答案:
@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
这个程序的字段数没有任何限制。 此版本要求在引号中加入可能有空格或其他批量分隔符的元素,但是这个限制可能很容易修复。
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命令外壳。 好吧。
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