非常抱歉,如果已经有人提出并回答了这个问题。我浏览了类似标题的问题,但没有找到似乎适用于我的问题。另外,这是我在 Stack Overflow 上发布的第一个问题。
我有一个名为 sortcriteria.csv 的 csv 文件,目前包含 12 列和 5 行。
这里是csv文件的内容:
Private,ReadWriteInc,TheArts,Preschool,Transition,Staff,Music,Language,MultiYearOrGroups,MiddleYears,PhysicalActivity,StudentLeaders
PLT,RWI,Art,Pre,Tran,Staff,Uke,Language,Group,MiddleYears,PhysicalActivity,StudentLeaders
Personal,",",",",",Ukulele,Japanese,",",PE,"
Private,",",",",",Guitar,German,",",","
11 ,",",",",",Music,",",",","
如果我在分隔符设置为逗号的情况下通过
for /f
循环运行它,我可以获得 12 个标记,每列一个。
例如,以下代码将生成 12 个变量:
for /f "delims=, tokens=1-12" %%B in (C:\GAMWork\sortcriteria.csv) do ...
对于当前形式的 sortcriteria.csv,此
for
循环将迭代 5 次(每行一次),每次生成 12 个变量(%%B
到 %%M
)。它会这样做,因为我已经告诉它有 12 列或标记,带有 "tokens=1-12"
.
但是,csv 文件可能并不总是有 12 列。将来可能会添加或减少列。 如何让批处理文件首先计算 csv 文件中的列数,然后使用该数字确定
for /f
循环查找的标记数?
我希望有以下内容:
<some code block that counts the number of columns in the csv file>
set /a tknnum=<Result from code block above>
for /f "delims=, tokens=1-%tknnum%" %%B in (C:\GAMWork\sortcriteria.csv) do ...
我特别希望我可以将列数设置为
tknnum
变量,因为我还需要在批处理文件的其他地方使用它用于其他目的。
我希望这个解释是清楚易懂的。
我没有任何尝试过的例子,因为我真的不知道从哪里开始尝试解决方案。 我想不出一种使用
for /f
来计算列数的 csv 文件的方法。
我已经从 Microsoft 的网站以及 ss64.com 阅读了 for
命令的文档。
如前所述,我还在 Stack Overflow 上搜索了类似标题的其他问题。在我能理解的那些中,似乎没有一个适用于我的上下文。
我能找到的最接近的是这个:https://stackoverflow.com/a/72903742/,但是我在试图理解@Magoo 的回答时迷路了。
编辑:我意识到使用
"
作为空白单元格的填充物是一个坏主意。对不起
到目前为止回答你的问题:
通过仅计算元素来获取列数(使用第一行,即标题)(注意:这使用标准分隔符(不可更改),因此如果列中应该有空格,则必须引用该值(像
"Student Leaders"
.
@echo off
<sortcriteria.csv set /p header=
set columns=0
for %%a in (%header%) do set /a columns+=1
echo Your file has %columns% columns.
for /f "tokens=1-%columns% delims=," %%a in (sortcriteria.csv) do ...
悬而未决的问题:你仍然不知道哪个字母是你的最后一个标记。可能有更好的解决方案。你到底想做什么?
构建带逗号和不带逗号的行的长度差异。
setlocal EnableDelayedExpansion
set /p firstLine= < file.csv
call :strlen firstLine totalLength
set "reduced=!firstLine:,=!"
call :strlen firstLine LengthWithoutCommas
set /a tknnum=totalLength-LengthWithoutCommas+1
echo %tknum%
exit /b
:strlen <stringVar> <resultVar>
(
setlocal EnableDelayedExpansion
(set^ tmp=!%~1!)
if defined tmp (
set "len=1"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!tmp:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "tmp=!tmp:~%%P!"
)
)
) ELSE (
set len=0
)
)
(
endlocal
set "%~2=%len%"
exit /b
)
但是正如@Stephan 已经提到的那样,计数可能帮助不大。
这是一个为每一行构建一个数组的解决方案
@echo off
setlocal EnableDelayedExpansion
(set LF=^
%=empty=%
)
set lineNumber=0
for /f "delims=" %%B in (%filename%) DO (
set /a lineNumber+=1
set count=0
set "CSV=%%B"
echo [!lineNumber!]: !CSV!
for %%L in ("!LF!") do set "CSV=!CSV:,=%%~L!"
FOR /F "tokens=* delims=" %%a in ("!CSV!") DO (
set /a count+=1
echo Column[!count!]: "%%a"
set "content[!line!][!column!]=%%a"
)
)
这是另一种,也许更简单的方法:
@echo off
set /P "header=" < sortcriteria.csv
set tokens=1 & set "col=%header:,=" & set /A tokens+=1 & set "col=%"
echo Tokens=%tokens%
此方法将指定字符精确作为分隔符(在本例中为逗号,与
for /F
命令相同),因此您可以在列中插入空格或制表符。
如果你不知道你的文件有多少列,你就不知道使用了哪些字母标记。下面的程序将字母标记转换为数组元素,因此您可以通过其下标使用任何数组元素和/或将元素的处理限制为下标不大于标记的元素:
@echo off
setlocal EnableDelayedExpansion
rem Count the tokens in file
set /P "header=" < sortcriteria.csv
set tokens=1 & set "col=%header:,=" & set /A tokens+=1 & set "col=%"
echo Tokens=%tokens%
rem Define the conversion from tokens to array elements
set "letter= abcdefghijklmnopqrstuvwxyz"
set "TokensToArray="
for /L %%i in (1,1,%tokens%) do (
set "TokensToArray=!TokensToArray!& set "array[%%i]=%%!letter:~%%i,1!" "
)
set "TokensToArray=!TokensToArray:~1!"
rem Process the file
for /F "tokens=1-%tokens% delims=," %%a in (sortcriteria.csv) do (
%TokensToArray%
echo -------------------------
echo Column 1 = "!array[1]!"
echo Column 7 = "!array[7]!"
)
输出:
Tokens=12
-------------------------
Column 1 = "Private"
Column 7 = "Music"
-------------------------
Column 1 = "PLT"
Column 7 = "Uke"
-------------------------
Column 1 = "Personal"
Column 7 = "Ukulele"
-------------------------
Column 1 = "Private"
Column 7 = "Guitar"
-------------------------
Column 1 = "11 "
Column 7 = "Music"