CSV解析

我正在尝试使用C#来解析CSV。 我使用正则表达式来查找","并且如果我的标题计数等于我的匹配计数则读取字符串。

如果我有一个像这样的值,这将不起作用:

 "a",""b","x","y"","c" 

然后我的输出是:

 'a' '"b' 'x' 'y"' 'c' 

但我想要的是:

 'a' '"b","x","y"' 'c' 

我可以使用任何正则表达式或任何其他逻辑吗?

CSV,在处理多行,引用,不同分隔符*等事情时,可能会比你想象的更棘手……或许考虑一个预先回答的答案? 我用它,效果很好。

* =记住某些区域设置使用[tab]作为CSV中的C …

CSV是代码重用的一个很好的例子 – 无论你选择哪一个csv解析器,都不要选择自己的。 停止滚动您自己的CSV解析器

如果我是你,我会使用FileHelpers 。 正则表达式很好但很难阅读,特别是如果你过一段时间后回去快速修复。

只是为了锻炼我的思维,快速和肮脏的工作 C#程序:

 public static List SplitCSV(string line) { if (string.IsNullOrEmpty(line)) throw new ArgumentException(); List result = new List(); bool inQuote = false; StringBuilder val = new StringBuilder(); // parse line foreach (var t in line.Split(',')) { int count = t.Count(c => c == '"'); if (count > 2 && !inQuote) { inQuote = true; val.Append(t); val.Append(','); continue; } if (count > 2 && inQuote) { inQuote = false; val.Append(t); result.Add(val.ToString()); continue; } if (count == 2 && !inQuote) { result.Add(t); continue; } if (count == 2 && inQuote) { val.Append(t); val.Append(','); continue; } } // remove quotation for (int i = 0; i < result.Count; i++) { string t = result[i]; result[i] = t.Substring(1, t.Length - 2); } return result; } 

为了获得可解析的CSV文件,值中的任何双引号都需要以某种方式正确转义。 执行此操作的两种标准方法是将双引号表示为两个双引号,或反斜杠双引号。 这是以下两种forms之一:

“”

\”

在第二种forms中,您的初始字符串将如下所示:

“一”, “\” B \ “\ ”×\“,\ ”Y \“”, “c” 的

如果您的输入字符串没有按照这样严格的格式进行格式化,那么您在自动化环境中成功解析它的可能性很小。

如果保证所有值都在引号中,请查找值,而不是逗号:

 ("".*?""|"[^"]*") 

这利用了“最早的最长匹配胜利”这一事实 – 它首先查找双引号值,并且正常引用值的优先级较低。

如果您不希望封闭引号成为匹配的一部分,请使用:

 "(".*?"|[^"]*)" 

并转到匹配组1中的值。

正如我所说的:这项工作的先决条件是格式良好的输入,每个值周围都有保证引号或双引号。 必须引用空值! 一个很好的副作用是它不关心分隔符char。 你可以用逗号,TAB,分号,空格命名。 一切都会奏效。

有一句经常引用说:

有些人在遇到问题时会想“我知道,我会使用正则表达式”。 现在他们有两个问题。 (Jamie Zawinski)

鉴于CSV文件没有官方标准(而是存在大量略微不兼容的样式),您需要确保实现的内容适合您将接收的文件。 实现比你需要的更好的东西没有意义 – 我很确定你不需要正则表达式。

这是我用一种简单的方法来提取术语 – 基本上,它循环遍历查找逗号的行,跟踪当前索引是否在字符串中:

  public IEnumerable SplitCSV(string line) { int index = 0; int start = 0; bool inString = false; foreach (char c in line) { switch (c) { case '"': inString = !inString; break; case ',': if (!inString) { yield return line.Substring(start, index - start); start = index + 1; } break; } index++; } if (start < index) yield return line.Substring(start, index - start); } 

标准警告 - 未经测试的代码,可能存在逐个错误。

限制

  • 不会自动删除值周围的引号。
    要执行此操作,请在结束时的yield return语句之前添加一个检查。

  • 不支持单引号与双引号相同
    您可以在inSingleQuotedString添加单独的布尔值,将现有布尔值重命名为inDoubleQuotedString并以相同的方式处理它们。 (你不能让现有的boolean做双重工作,因为你需要字符串以启动它的相同引号结束。)

  • 空格不会自动删除
    有些工具会在CSV文件的逗号周围引入空格,以“漂亮”文件; 然后很难从格式化空格中分辨出有意的空格。

FileHelpers支持多行字段。

您可以解析这些文件:

 a,"line 1 line 2 line 3" b,"line 1 line 2 line 3" 

这是数据类型声明:

 [DelimitedRecord(",")] public class MyRecord { public string field1; [FieldQuoted('"', QuoteMode.OptionalForRead, MultilineMode.AllowForRead)] public string field2; } 

这是用法:

 static void Main() { FileHelperEngine engine = new FileHelperEngine(typeof(MyRecord)); MyRecord[] res = engine.ReadFile("file.csv"); } 

尝试CsvHelper (我维护的库)或FastCsvReader 。 两者都运作良好。 CsvHelper也写作。 像其他人一直在说的那样,不要自己动手。 :P

.Net的FileHelpers是你的朋友。

请点击“使用CSV进行正则表达式”链接:

http://snippets.dzone.com/posts/show/4430

Lumenworks CSV解析器(开源,免费但需要代码项目登录)是迄今为止我用过的最好的解析器。 这将节省您必须编写正则表达式并且直观易用。

好吧,我不是正则表达式,但我确信他们有这个答案。

程序上它正在逐字逐句地进行。 将变量(例如dontMatch)设置为FALSE。

每次你遇到报价切换dontMatch。

每次遇到逗号时,请检查dontMatch。 如果为TRUE,则忽略逗号。 如果为FALSE,则以逗号分隔。

这适用于您给出的示例,但您用于引号的逻辑基本上是错误的 – 您必须转义它们或使用其他分隔符(例如,单引号)来设置除小引号之外的主要引号。

例如,

"a", ""b", ""c", "d"", "e""

会产生不好的结果。

这可以用另一个补丁修复。 而不是简单地保持真假,你必须匹配报价。

要匹配引号,您必须知道上次看到的内容,它会进入相当深的解析区域。 在那时,您可能希望确保您的语言设计得很好,如果是,您可以使用编译器工具为您创建解析器。

-亚当

我只是在我的代码中尝试你的正则表达式。对于带有引号的格式化文本工作正常…

但是想知道我们是否可以通过Regex解析价值低于…

 “First_Bat7679”,“”NAME“,”ENAME“,”FILE“”,“”,“”,“来自:”DDD,_Ala%as“@ sib.com”

我正在寻找结果:

 'First_Bat7679'
 ' “名称”, “ENAME”, “程序文件”'
 “”
 “”
 '来自:“DDD,_Ala%为”@ sib.com“

感谢名单