我正在努力编写一个可以读取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个令牌。请帮助!
答案 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