【问题标题】:Batch: Convert .csv to tab-delimited text, only some fields are quoted, contain commas between quotes (eBay order file)批处理:将 .csv 转换为制表符分隔的文本,仅引用部分字段,引号之间包含逗号(eBay 订单文件)
【发布时间】:2013-12-18 16:49:48
【问题描述】:

我正在尝试将 eBay File Exchange 下载转换为我的运输软件可以读取的制表符分隔格式。

如果每一列都被引用,这很容易——但事实并非如此。只有一些列(名称、项目列表标题等)被引用,一些被引用的列包含逗号。其余的都没有引号。

我需要一种在 .bat 文件中解析和转换它的方法,但是如果引用的字段也包含逗号,则使用逗号作为分隔符会拆分它们,从而给我不可用的数据。我确定有一个简单的解决方法,我就是想不通。

【问题讨论】:

  • 发送您的.CSV 文件示例和您需要的输出。
  • 在测试时解析几行文件以进行操作总是有帮助的。很明显,只是格式。

标签: batch-file comma csv quotation-marks


【解决方案1】:

Eric J 是对的——用批处理解决这类问题并不简单。但这是可能的:-)

主要问题是如何区分带引号和不带引号的逗号 - jeb 在'Pretty print' windows %PATH% variable - how to split on ';' in CMD shell 解决了带引号和不带引号的分号的类似问题。下面的代码看起来很不一样,但基本概念是一样的。

只要所有行的长度小于 ~8000 字节,下面的代码几乎适用于任何 CSV。批处理变量值限制为 8191 字节,部分字符临时扩展为两个字节。

代码假定 CSV 文件中没有任何现有的 TAB。

它不会修改任何现有的引号。

正如我所说,代码应该可以工作,但是如果您有一个大文件,它会非常缓慢。按照 Eric J 的建议,使用 .NET 解决方案会更好。

@echo off
setlocal disableDelayedExpansion

set "file=optionalPathinfo\yourFile.csv"

:: Define a TAB variable
for /f "delims=" %%A in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"'
) do set "TAB=%%A"


:: Read each line from CSV, convert it, and write to new file with .new extension
>"%file%.new" (
  for /f usebackq^ delims^=^ eol^= %%A in ("%file%") do (
    set "line=%%A"
    call :processLine
  )
)
exit /b


:processLine
setlocal enableDelayedExpansion

:: Protect problem characters
set "line=!line:@=@A!"
set "line=!line:^=@K!"
set "line=!line:&=@M!"
set "line=!line:|=@P!"
set "line=!line:<=@L!"
set "line=!line:>=@G!"

:: Mark commas with leading caret (escape)
set "line=!line:,=^,!"

:: Remove mark from unquoted commas, but first temporarily
:: disable delayed expansion to protect any ! characters
setlocal disableDelayedExpansion
set ^"line=%line%"
setlocal enableDelayedExpansion

:: Protect remaining marked commas
set "line=!line:^,=@C!"

:: Convert remaining commas to TAB
set "line=!line:,=%TAB%!"

:: Restore protected characters
set "line=!line:@C=,!"
set "line=!line:@G=>!"
set "line=!line:@L=<!"
set "line=!line:@P=|!"
set "line=!line:@M=&!"
set "line=!line:@K=^!"
set "line=!line:@A=@!"

:: Write modified line
echo(!line!
exit /b

【讨论】:

  • 该文件的订单永远不会超过两周——所以 200 行或更少。我会试一试,然后报告。
  • 好的,这行得通。正如你所说,这需要一段时间,但它确实有效。现在我只需要将它与标准的开始日转换结合起来。
  • 我遇到了在循环中耗尽“setlocal”的问题。尽管此代码没有循环,而是“调用”,但当您执行“setlocal disableDelayedExpansion”时,应该执行匹配的 endlocal 来结束本地化。只是说,作为临时编码人员可能会产生对编码的误解。你会同意吗? “exit /b”是否会隐式清除所有发出的“setlocal”命令?为什么在命令“echo(0x09”和“echo(!line!”)中使用“(”而不是空格字符。“(”有什么作用吗?
  • ENDLOCAL 不是必需的,因为是的,EXIT /B(实际上,任何形式的退出脚本或例程)对例程内发出的所有活动SETLOCAL 执行隐式ENDLOCALECHO( 防止“ECHO 关闭”。如果以下文本为空或只有空白,则不会出现消息。 ECHO. 更常用,但在一些模糊的场景中可能会失败。 ECHO( 是唯一保证在所有情况下都有效的形式。
  • 学习新东西总是好的。 :-) 再问一个问题,为什么 set ^"line=%line%" 中的第一个双引号会出现脱字符转义,而第二个双引号也不会出现脱字符?
【解决方案2】:

还有一个更复杂的情况:带有引号和逗号的字段也会使引号转义:

Jim “Smitty” Smith, Jr.

将在 CSV 文件中表示为

“吉姆”“Smitty”“小史密斯”

这不是在批处理文件中容易解决的问题。但是,已有处理 CSV 格式的功能,可用于任何 .NET 兼容语言,包括Powershell。如果这是一个选项,请查看

http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

有关调用 .NET 方法从 Powershell 读取 CSV 文件的信息,请查看

http://blogs.msdn.com/b/mattbie/archive/2010/02/23/how-to-call-net-and-win32-methods-from-powershell-and-your-troubleshooting-packs.aspx

【讨论】:

  • +1,我同意批处理不是解决这个问题的好选择。但它可以做到:-) 见我的回答。
猜你喜欢
  • 1970-01-01
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-05
  • 2018-07-17
相关资源
最近更新 更多