【问题标题】:Parsing commas and quotemarks in degenerate CSV files with Regular Expressions使用正则表达式解析退化 CSV 文件中的逗号和引号
【发布时间】:2010-03-27 20:07:31
【问题描述】:

我需要解析字符串输入,其中列由列分隔,并且数据中包含逗号的任何字段都用引号引起来(逗号分隔,带引号的文本标识符)。对于这个项目,我需要删除引号和引号之间出现的任何逗号。基本上,我需要删除字段中包含的逗号和引号,同时保留用于分隔字段的逗号。这是我整理的一些处理简单场景的小代码:

// Sample input 1: This works and covers 99% of the records that I need to parse.
string str1 = "an_email_address@somewhere.com,2010/03/27 12:2:02,,some_first_name,some_last_name,,\"This Address Works, Suite 200\",Some City,TN,09876-5432,9795551212x123,XYZ";
str1 = Regex.Replace(str1, "\"([^\"^,]*),([^\"^,]*)\"", "$1$2");
Console.WriteLine(str1);
// Outputs: an_email_address@somewhere.com,2010/03/27 12:2:02,,some_first_name,some_last_name,,This Address Works Suite 200,Some City,TN,09876-5432,9795551212x123,XYZ

虽然此代码适用于我的大部分记录,但当字段包含多个逗号时它不起作用。我想做的是修改代码,以便删除列中包含的每个逗号实例,无论字段中有多少逗号。我不想硬编码只处理 2 个逗号、3 个逗号或 25 个逗号。代码应该只删除该字段中的所有逗号。以下是我的代码无法正确处理的示例。

// Sample input 2: This doesn't work since there is more than 1 comma between the quotes.
string str2 = "an_email_address@somewhere.com,2010/03/27 12:2:02,,some_first_name,some_last_name,,\"i,l,k,e, c,o,m,m,a,s, i,n ,m,y, f,i,e,l,d\",Some City,TN,09876-5432,9795551212x123,XYZ";
str2 = Regex.Replace(str2, "\"([^\"^,]*),([^\"^,]*)\"", "$1$2");
Console.WriteLine(str2);
// Desired output: an_email_address@somewhere.com,2010/03/27 12:2:02,,some_first_name,some_last_name,,i like commas in my field,Some City,TN,09876-5432,9795551212x123,XYZ

我怎样才能用正则表达式做到这一点?

【问题讨论】:

  • 您描述的格式与 CSV 完全匹配。为什么不使用现有的 CSV 解析器?
  • 我正在使用 SSIS 导入几千个遗留日志文件。但是,这些文件存在数据质量问题。有些文件有 13 列,有些有 14 列,有些使用引号包含逗号的文本字段,有些不使用引号并产生“额外”列等。我已经描述了更多问题,但我已经能够在我的数据流中使用脚本转换来处理所有这些问题——除了帖子中描述的问题。

标签: c# regex


【解决方案1】:

匹配引号和正则表达式不能并存,正如 Michael Madsen 建议的那样,您可能最好使用 CSV 解析器。
但是,如果您知道引号只会按预期出现,则可以执行以下操作:

str2 = Regex.Replace(str2, "\"[^\"]*\"",
                     match => match.Value.Trim('\"').Replace(",", ""));

【讨论】:

  • 最后一位不应该是.Replace(",", "")吗?
  • @注册用户 - 谢谢!顺便说一句,这是一个 lambda 表达式 - 一个匿名函数,就像以前 C# 版本中的 delegate 一样。在某种程度上,它确实会查看匹配项,但以一种微妙的方式。
【解决方案2】:

这是一个纯正则表达式版本:

str2 = Regex.Replace(str0, 
          @"""|,(?=(?>[^""]*""[^""]*(?:""[^""]*""[^""]*)*)$)", 
          String.Empty);

它匹配任何引号,如果它后跟奇数个引号,则匹配逗号,并将其替换为空。

如果我绝对必须这样做,我只会走这条路,例如,如果我正在使用一个只让我指定正则表达式和替换字符串的框架。否则,我要么采用@Kobi 的方法(因为它更具可读性),要么使用专用的 CSV 处理器。它们并不难找到。

【讨论】:

  • 我采用了 Kobi 的方法,因为它不必仅限于正则表达式。我只是假设必须有一种使用正则表达式的方法,因为它似乎是解决问题的合适工具。不过,我肯定会剖析你的代码,看看我是否能理解它并从中学到一些有用的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多