使用批处理文件,如何确定CSV文件中的字段数?

使用批处理文件,如何确定CSV文件中的字段数?,csv,regex,windows,batch-file,cmd,Csv,Regex,Windows,Batch File,Cmd,我从一个文件中得到一条记录(行),需要输出它包含的字段数(列) 例如,(包括空字段): a,b,,d,,,f ----------- = 7 columns 我考虑过计算记录中字段分隔符(逗号)的数量,但字段数据也可能包含逗号 正则表达式是否适合此任务?使用awk脚本如下: echo "a,b,,d,,,f" | awk -F"," '{print NF}' 鉴于CSV单元格仅包含可打印字符,且引号“用于括起包含,的文本,您可以执行以下步骤: 读一行 删除有问题的通配符(不干扰以后的)

我从一个文件中得到一条记录(行),需要输出它包含的字段数(列)

例如,(包括空字段)

a,b,,d,,,f
-----------
= 7 columns 
我考虑过计算记录中字段分隔符(逗号)的数量,但字段数据也可能包含逗号


正则表达式是否适合此任务?

使用
awk
脚本如下:

echo "a,b,,d,,,f" | awk -F"," '{print NF}'

鉴于CSV单元格仅包含可打印字符,且引号
用于括起包含
的文本,您可以执行以下步骤:

  • 读一行
  • 删除有问题的通配符(不干扰以后的
  • 移除除
    之外的标准令牌分隔符(以使
    仅在未引用的
    之后分离)
  • 用引号将每个字段括起来
  • 对字段进行循环(使用
    进行
    )并对其进行计数
以下代码可用于此目的(CSV数据应位于作为第一个命令行参数给出的文件中):

@echo关闭
setlocal EnableExtensions DisableDelayedExpansion
rem//聚集选项卡字符:
对于/F“delims=“%%C in('forfiles/P“%~dp0.”/M“%~nx0”/C“cmd/C echo/0x09”),请设置“TAB=%%C”
rem//逐行读取CSV文件:
对于/F usebackq^delims^=^eol^=%%L in(“%1”)do(
rem//存储当前行字符串:
设置“行=%%L”
rem//切换延迟扩展以避免出现“!”问题:
setlocal EnableDelayedExpansion
rem//删除有问题的通配符“?”,“`”:
设置“测试=!行:?=!”&设置“测试=!测试:=!”
rem//删除标准令牌分隔符空间,选项卡,`;`,但不,`:
设置“测试=!测试:=!”&设置“测试=!测试:%TAB%=!”&设置“测试=!测试:;=!”
rem//删除特殊字符“!”、“^”、“*”、“=”:
调用:删除测试
rem//将所有字段用引号括起来,循环并计数:
设置/A“计数=0”&对于(“!TEST:,=”,“!”)中的%%I,设置/A“计数+=1”
rem//返回字段和行的计数:
回声!计数!:!线路!
端部
)
端部
退出/B
:删除
setlocal DisableDelayedExpansion
设置“#RET=%~1”&如果未定义#RET endlocal&exit/B 2
设置“#STR=%~2”&如果未定义#STR set“#STR=%#RET%”
设置“RPL=^*="
setlocal EnableDelayedExpansion
设置“BUF=”&设置“TST=!%#STR%!“&set”WRK=!TST_"
:移除循环
如果未定义TST集“BUF=!巴夫:~1,-1!“&转到:删除\u下一步”
对于(“!BUF!!WRK!”)中的/F“tokens=1*delims=%RPL%eol=%RPL:~,1%”%%S,请执行以下操作(
endlocal&设置“BUF=%%S”&设置“TST=%%T”&设置“WRK=%%T”&设置本地启用延迟扩展
)
转到:删除循环
:下一步移除
对于/F“delims=“%%S in(^”“!BUF!”^”)执行endlocal&endlocal&set“%\RET%=%%~S”
退出/B
输入数据示例:

unquoted,“quoted”,unquoted空格,“quoted空格”,“quoted,逗号”,unquoted;&|!^,“quoted;&|^,(不带引号的参数),(带引号的参数),,下一个空,星号*,等于
输出文本示例:

14:unquoted,“quoted”,unquoted空格,“quoted空格”,“quoted,逗号”,unquoted;&|!^,“quoted;&|^,(不带引号的参数),(带引号的参数),,下一个空,星号*,等于

您需要[string]的长度和[string without commas]的长度。 以下是一个简单的实现:

@echo off
set "line=a,b,,d,,,f"
>one.tmp echo %line%
>two.tmp echo %line:,=%
for %%a in (one.tmp) do set one=%%~za
for %%a in (two.tmp) do set two=%%~za
set /a commas=one-two
echo %commas% commas
寻找替代方法来获取没有临时文件的字符串长度

Edit昨晚我似乎没有检查您对值中逗号的担忧。一个简单的
for
循环解决了这个问题:

@echo off
setlocal
set "line=1,2,,"4,0",5"
echo original line: %line%
set cols=0
for %%a in (%line:,=X,X%) do set /a cols+=1
echo counted columns: %cols%

假设变量中已有代表行,则以下纯批处理可以可靠地确定字段数,前提是任何字段都不包含换行符。Microsoft spec for CSV允许在字段中使用换行符,但很少使用,因此可以忽略此问题

该代码允许字段中的任何其他字符,并说明字段中带引号的逗号文字,以及表示引号文字的双引号

该算法是a的派生。在这种情况下,
是一个分隔符,但引用的路径可以包含
文本

@echo关闭
setlocal
设置“行=,,!,”,,!,,1,2,4,0,5,a,b,c
设定线
setlocal enableDelayedExpansion
::删除所有有毒字符
如果定义了行,则设置“行=!行:^=!"
如果定义了行,则设置“行=!行:=!"
如果定义了行,则设置“行=!行:|=!"
如果定义了行,则设置“行=!行:&=!"
::全部删除!
如果定义了行,则设置“行=%line:!=%"
::将所有true分隔符转换为^,-注意,引号会导致分隔符被引用
::中的值也会被转换,但它们不再被引用,因此会恢复为,
如果定义了行,则设置“行=%line:,=^,%”
::将^,分隔符转换为换行符
对于%%N英寸(^”^
%=这将创建带引号的换行符=%
^)如果定义行设置为“行=!行:^,=%%~N!"
::计算字符串中的行数并保存结果
setlocal disableDelayedExpansion
对于/f%%N in('cmd/v on/c echo(!line!^ find/c/v”“),请设置“cnt=%%N”
回显%cnt%字段
--输出--

line=,,,,,,,,,,,,“4,!0,,,5,,“a”,“b”,“c”,,
13个字段

有关如何正确批量读取CSV文件的信息,请参见。Stephan,请注意,我已对问题进行了编辑,在示例记录中包含了一条关于空字段的语句。我以前认为没有必要提及(示例已足够),但考虑到您最近的编辑,我已经澄清了一些事情;对不起!我想今天早上的咖啡不够浓……简单的更改。请参阅我的编辑。不,如果任何值包含
*
和/或
通配符,则仍然存在潜在问题如果未引用的值包含
&
@dbenham也包含
,则存在问题>=
甚至空格。我根据问题中的示例确定了代码的方向