windows - Windows批处理脚本以解析CSV文件并输出文本文件

标签 windows csv batch-file cmd

我在另一页(Help in writing a batch script to parse CSV file and output a text file)上看到了响应-出色的代码BTW:

@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

它对于以下格式的示例csv文件非常有用:
Header,Name,Place
one,two,three
four,five,six

但是,我要更改的实际文件包含64个字段-因此我将tokens=1-10更改为tokens=1-64,并增加了%%a等,最多可包含64个变量(例如,最后一个称为%%BL)。但是,现在,当我在“大” csv文件(带有64个 token )上运行批处理时,什么也没发生。没有错误(良好),但没有输出! (坏的)。如果有人可以帮忙,那真是太棒了……如果我能确定这最后一点,我将使整个应用程序正常工作!或者,如果有人有一些示例代码将对无限数量的标记执行类似的操作……最终,我想制作一个类似于以下内容的字符串:
field7,field12,field15,field18

最佳答案

重要更新-我认为Windows批处理不是满足您需求的好选择,因为单个FOR/F不能解析超过31个 token 。有关说明,请参见下面的附录底部。

但是,可以批量处理所需的操作。这个丑陋的代码将使您能够访问所有64个 token 。

for /f "usebackq tokens=1-29* delims=," %%A in ("%filename%") do (
  for /f "tokens=1-26* delims=," %%a in ("%%^") do (
    for /f "tokens=1-9 delims=," %%1 in ("%%{") do (
      rem Tokens 1-26 are in variables %%A - %%Z
      rem Token  27 is in %%[
      rem Token  28 is in %%\
      rem Token  29 is in %%]
      rem Tokens 30-55 are in %%a - %%z
      rem Tokens 56-64 are in %%1 - %%9
    )
  )
)

附录提供了有关上述工作原理的重要信息。

如果您只需要在行中的64个 token 中散布一些 token ,那么该解决方案将稍微容易一些,因为您可以避免使用疯狂的字符作为FOR变量。但是,仍然需要仔细进行簿记。

例如,以下内容将使您可以访问 token 5、27、46和64
for /f "usebackq tokens=5,27,30* delims=," %%A in ("%filename%") do (
  for /f "tokens=16,30* delims=," %%E in ("%%D") do (
    for /f "tokens=4 delims=," %%H in ("%%G") do (
      rem Token  5 is in %%A
      rem Token 27 is in %%B
      rem Token 46 is in %%E
      rem Token 64 is in %%H
    )
  )
)

2016年4月更新-基于DosTips用户Aacini,penpen和aGerman的调查工作,我开发了一种相对简单的方法,可以使用FOR/F同时访问数千个 token 。该作品是this DosTips thread的一部分。实际的代码可以在以下3个帖子中找到:
  • Work with a fixed number of columns
  • Work with varying numbers of columns
  • Dynamically choose which tokens to expand within the DO clause

  • 原始答案
    FOR变量限制为单个字符,因此您的%% BL策略无法正常工作。变量区分大小写。根据Microsoft的说法,您只能在一个FOR语句中捕获26个 token ,但是如果您使用的不只是alpha,则有可能获得更多。这很麻烦,因为您需要一个ASCII表来确定哪些字符在哪里。但是,FOR不允许仅使用任何字符,并且单个FOR/F可以分配的最大 token 数为31 +1。正如您所发现的那样,任何尝试分析和分配31个以上的尝试都将悄然失败。

    值得庆幸的是,我认为您不需要那么多 token 。您只需使用“ token ”选项指定所需的 token 。
    for /f "usebackq tokens=7,12,15,18 delims=," %%A in ("%filename%") do echo %%A,%%B,%%C,%%D
    

    将为您提供第7、12、15和18个 token 。

    附录

    ,2016年4月更新,几周前,我了解到以下规则(6年前编写)取决于代码页。已针对代码页437和850验证了以下数据。更重要的是,扩展ASCII字符128-254的FOR变量序列与字节代码值不匹配,并且因代码页而异。事实证明,FOR/F变量映射基于基础UTF-(16?)代码点。因此,与FOR/F一起使用时,扩展的ASCII字符的使用受到限制。有关更多信息,请参见http://www.dostips.com/forum/viewtopic.php?f=3&t=7703上的线程。

    我进行了一些测试,并且可以报告以下内容(根据jeb的评论进行了更新):

    大多数字符都可以用作FOR变量,包括扩展的ASCII 128-254。但是某些字符不能用于在FOR语句的第一部分中定义变量,而可以在DO子句中使用。几个都不能使用。有些没有限制,但是需要特殊的语法。

    以下是有限制或需要特殊语法的字符的摘要。请注意,尖括号内的文本(例如<space>)表示单个字符。
    Dec  Hex   Character   Define     Access
      0  0x00  <nul>       No         No
     09  0x09  <tab>       No         %%^<tab>  or  "%%<tab>"
     10  0x0A  <LF>        No         %%^<CR><LF><CR><LF>  or  %%^<LF><LF>
     11  0x0B  <VT>        No         %%<VT>
     12  0x0C  <FF>        No         %%<FF>
     13  0x0D  <CR>        No         No
     26  0x1A  <SUB>       %%%VAR%    %%%VAR% (%VAR% must be defined as <SUB>)
     32  0x20  <space>     No         %%^<space>  or  "%%<space>"
     34  0x22  "           %%^"       %%"  or  %%^"
     36  0x24  $           %%$        %%$ works, but %%~$ does not
     37  0x25  %           %%%%       %%~%%
     38  0x26  &           %%^&       %%^&  or  "%%&"
     41  0x29  )           %%^)       %%^)  or  "%%)"
     44  0x2C  ,           No         %%^,  or  "%%,"
     59  0x3B  ;           No         %%^;  or  "%%;"
     60  0x3C  <           %%^<       %%^<  or  "%%<"
     61  0x3D  =           No         %%^=  or  "%%="
     62  0x3E  >           %%^>       %%^>  or  "%%>"
     94  0x5E  ^           %%^^       %%^^  or  "%%^"
    124  0x7C  |           %%^|       %%^|  or  "%%|"
    126  0x7E  ~           %%~        %%~~ (%%~ may crash CMD.EXE if at end of line)
    255  0xFF  <NB space>  No         No
    

    特殊字符(例如^ < > | &)必须转义或加引号。例如,以下工作:
    for /f %%^< in ("OK") do echo "%%<" %%^<
    

    某些字符不能用于定义FOR变量。例如,以下给出了语法错误:
    for /f %%^= in ("No can do") do echo anything
    

    但是可以使用TOKENS选项隐式定义%%=,并在DO子句中访问该值,如下所示:
    for /f "tokens=1-3" %%^< in ("A B C") do echo %%^< %%^= %%^>
    
    %是奇数-您可以使用%%%%定义一个FOR变量。但是,除非使用~修饰符,否则无法访问该值。这意味着不能保留引号。
    for /f "usebackq tokens=1,2" %%%% in ('"A"') do echo %%%% %%~%%
    

    上面产生%% A~是潜在危险的FOR变量。如果尝试在行尾使用%%~访问变量,则可能会得到无法预料的结果,甚至可能使CMD.EXE崩溃!不受限制地访问它的唯一可靠方法是使用%%~~,它当然会去除所有封闭的引号。
    for /f %%~ in ("A") do echo This can crash because its the end of line: %%~
    
    for /f %%~ in ("A") do echo But this (%%~) should be safe
    
    for /f %%~ in ("A") do echo This works even at end of line: %%~~
    
    <SUB>(0x1A)字符是特殊字符,因为批处理脚本中嵌入的<SUB>文字被读取为换行符(<LF>)。为了将<SUB>用作FOR变量,必须以某种方式将值存储在环境变量中,然后%%%VAR%将同时用于定义和访问。

    如前所述,单个FOR/F可以解析和分配最多31个 token 。例如:
    @echo off
    setlocal enableDelayedExpansion
    set "str="
    for /l %%n in (1 1 35) do set "str=!str! %%n"
    for /f "tokens=1-31" %%A in ("!str!") do echo A=%%A _=%%_
    

    上面产生A=1 _=31注意- token 2-30正常工作,我只想举一个小例子

    如果不设置ERRORLEVEL,则任何试图解析和分配31个以上 token 的尝试都将无提示地失败。
    @echo off
    setlocal enableDelayedExpansion
    set "str="
    for /l %%n in (1 1 35) do set "str=!str! %%n"
    for /f "tokens=1-32" %%A in ("!str!") do echo this example fails entirely
    

    您最多可以解析并分配31个 token ,然后将其余 token 分配给另一个 token ,如下所示:
    @echo off
    setlocal enableDelayedExpansion
    set "str="
    for /l %%0 in (1 1 35) do set "str=!str! %%n"
    for /f "tokens=1-31*" %%@ in ("!str!") do echo @=%%A  ^^=%%^^  _=%%_
    

    上面产生@=1 ^=31 _=32 33 34 35
    现在是真正的坏消息。 正如我在查看Number of tokens limit in a FOR command in a Windows batch script时所了解的那样,单个FOR/F永远不能解析超过31个 token
    @echo off
    setlocal enableDelayedExpansion
    set "str="
    for /l %%n in (1 1 35) do set "str=!str! %%n"
    for /f "tokens=1,31,32" %%A in ("!str!") do echo A=%%A  B=%%B  C=%%C
    

    非常不幸的输出是A=1 B=31 C=%C

    关于windows - Windows批处理脚本以解析CSV文件并输出文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8520313/

    相关文章:

    c++ - Visual C++如何检测Windows更新是否正在运行?

    c++ - 适用于 Linux 的 SDL 跨平台消息框

    带有特殊字符的 Excel 到 CSV?

    Python:按包含符号的数字顺序对 .txt 文件的内容进行排序

    mysql - 错误代码 : 1193 unknown system variable when importing a CSV

    windows - 如何将任意字符串回显到批处理文件?

    asp.net - "Could not create SSL/TLS secure channel": how can the clone work?

    c - 在 Windows 上的 ubuntu 中使用 gdb 时段错误消失

    windows - 如何用另一个 .exe 包装对 .exe(带参数)的调用?

    c++ - 如何使用 Ghostscript 自动安装 RedMon