csv 如果执行不一致,则进行批处理

bejyjqdl  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(168)

我正在尝试使用if else语句设置一个变量。问题是else if "%%D"GEQ "%%G" (set var=%%G)执行不一致。我不确定是什么问题。
下面是我的代码:

@echo on
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1-8* delims=," %%A IN (results.csv) DO (
    if "%%D" equ 0 (
    set var=0
    ) else if "%%D" GEQ "%%G" (
    set var=%%G
    ) else (set var=%%D)
    set "y=%%A,%%B,%%C,%%D,%%E,%%F,%%G,%%H,!var!"
echo !y!>>final.csv
)

下面是我的输入文件的一个示例。

"01185901095","11","0379-0005","50","001","0","3","3"
"01185901215","11","0379-0013","138","001","0","4","2"

下面是我在final.csv中得到的输出

"01185901095","11","0379-0005","50","001","0","3","3","3"
"01185901215","11","0379-0013","138","001","0","4","2","138"

我的预期输出为:

"01185901095","11","0379-0005","50","001","0","3","3","3"
"01185901215","11","0379-0013","138","001","0","4","2","4"

输出中的第2行是问题所在。%%D大于%%G,因此我期望值为%%G(或者138大于4,因此我期望值为4)

insrf1ej

insrf1ej1#

应该先阅读我对Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files的回答,以全面了解cmd.exe的内部命令IF如何进行字符串比较(在此处完成),而不是预期的整数比较。
在处理输入CSV文件results.csv的第一行时,条件if "%%D" equ 0变为if ""50"" EQU 0,这导致将字符串""50""字符串0进行比较,因为值50周围有四个双引号。第一字符串""50""的第一字符"具有十进制字节值34,而第二字符串0的第一字符0具有十进制字节值48。由于该原因,所使用的函数lstrcmpW在将两个字符串的第一个字符与−1进行比较时已经退出。接下来,在与整数值0相等时比较该整数值,这与以下事实无关,即,在这里偶然地还对比较运算符EQU指定了正确的0。此条件的结果始终为false,与将哪个字符串分配给从文件results.csv读取的循环变量D无关,因为%%D周围的双引号始终导致字符"与字符0进行比较。
接下来总是执行if "%%D" GEQ "%%G",它在处理results.csv的第一行时导致字符串""50""字符串""3""的比较。两个被比较字符串的前两个字符相等。第一个字符串的第三个字符5的十进制字节值53大于第二个字符串的第三个字符3的十进制字节值51,并且由于该原因,串比较的结果是大于整数值0的整数值1,并且由于该原因,第二条件对于results.csv的第一行偶然正确为真。
但是在处理results.csv的第二行时,将字符串""138""与字符串""4""进行比较,其中第一个字符串的第三个字符的字节值小于第二个字符串的第三个字符的字节值。在这种情况下,字符串比较的结果是−1,它小于整数值0。尽管整数值138将大于整数值4,但对于处理CSV文件第二行中的值的第二个条件,比较结果为false
该解决方案根本不使用"围绕循环变量引用,另外还删除了从CSV文件读取的值周围的双引号,以真正运行整数值比较,而不是字符串比较,这意味着使用%%~D%%~G

@echo off
setlocal EnableExtensions EnableDelayedExpansion
(for /F "tokens=1-8* delims=," %%A in (results.csv) do (
    if %%~D EQU 0 (
        set var=0
    ) else if %%~D GEQ %%~G (
        set var=%%G
    ) else set var=%%D
    echo %%A,%%B,%%C,%%D,%%E,%%F,%%G,%%H,!var!
))>final.csv
endlocal

在上面的代码中,除了一些不太重要的小改进之外,还有一个更重要的性能修改:整个for循环被括在圆括号中,并且由循环内的命令echo输出到标准输出流的所有内容被写入文件final.csv中。
此代码的执行结果是首先打开文件final.csv以进行写操作,并且只要for正在处理从results.csv读取的下一行,就一直保持其打开,最后刷新final.csv的数据,并且在for完成并关闭文件results.csv之后关闭此文件。
对于从results.csv读取的每一行,所讨论的代码都将打开文件final.csv,查找到文件的结尾,使用命令echo附加行输出,然后关闭文件final.csv。这使得在results.csv中处理数千或数百万行的速度比上面的代码慢得多,尽管Windows的文件缓存机制实际上避免了编写在硬盘的每一行上打开、更改和关闭文件final.csv

**注意:**此处发布的代码仅在results.csv中没有空字段值的情况下有效,这意味着results.csv中没有包含,,的行。开始执行批处理文件时的当前目录必须是包含results.csv的目录,否则final.csv将是一个空文件。

mzmfm0qo

mzmfm0qo2#

我不太清楚您的一些比较的目的,所以纯粹基于最佳猜测,您的输入文件内容和您预期的输出内容,像这样的东西会不会做您想要的:

@(  For /F "UseBackQ EOL=, Delims=" %%G In ("results.csv"
    ) Do @For /F "Tokens=4,7 Delims=," %%H In ("%%~G"
    ) Do @If %%~H Gtr %%~I (Echo %%G,"%%~I") Else Echo %%G,"%%~H"
) 1>"final.csv"

正如您所看到的,不需要延迟扩展或定义变量。

相关问题