D:用逗号分割字符串,但不带引号的字符串

D: split string by comma, but not quoted string

我需要用逗号分隔字符串,而不是像这样引用: foo, bar, "hello, user", baz

获得:

foo
bar
hello, user
baz

您可以使用下一个片段来完成此任务:

File fileContent;
string fileFullName = `D:\code\test\example.csv`;
fileContent = File (fileFullName, "r");

auto r = regex(`(?!\B"[^"]*),(?![^"]*"\B)`); 
foreach(line;fileContent.byLine)
  {
   auto result = split(line, r);
   writeln(result);
  }

如果您要解析特定的文件格式,按行拆分和使用正则表达式通常是不正确的,尽管它在很多情况下都有效。我更喜欢逐个字符地阅读它,并为状态保留一些标志(或者在适当的情况下使用其他人的函数来为您完成这种格式)。 D 有 std.csv: http://dlang.org/phobos/std_csv.html or my old old csv.d which is minimal but basically works too: https://github.com/adamdruppe/arsd/blob/master/csv.d(哈哈 5 年前是我对它的最后一次更改,但是嘿,它仍然有效)

同样,你可以有点 "parse" html 使用正则表达式......有时,但它在简单情况之外很快就会崩溃,你最好使用实际的 html解析器(这可能是为了逐个字符读取字符而编写的!)

回到引号,例如阅读csv,有一些引号内容的规则:首先,当然,逗号可以出现在引号内,而不会转到下一个字段。其次,换行符也可以出现在引号内而无需转到下一行!第三,连续两个引号字符是内容中的转义引号,而不是结束引号。

foo,bar
"this item has
two lines, a comma, and a "" mark!",this is just bar

我不确定如何使用正则表达式读取它(目测,我很确定你的转义引号至少是错误的),但一次读取一个字符并不难(我的小 csv reader 大约有五十行,手工完成)。与仅阅读字符相比,提前拆分行也变得复杂,因为当您发现以结束引号结尾时,您可能不得不稍后重新组合行!然后你漂亮的 byLine 循环突然变得不那么漂亮了。

此外,当稍后回顾时,我发现简单的字符 readers 和命名函数无论如何比正则表达式更容易理解。

因此,对于您所询问的有限范围,您的答案是正确的,但可能缺少您实际尝试阅读的文件格式中其他情况的概况。

编辑:我想强调的最后一件事是,CSV 中的这些极端情况是人们经常说 "don't reinvent the wheel" 的一个例子。并不是说它们真的很难处理 - 看看我的 csv.d 代码,它很短,非常简单,并且可以处理我抛给它的所有东西 - 但这就是问题所在,不是吗? "Everything I've thrown at it"。要处理文件格式,您需要了解极端情况是什么,以便您可以处理它们,至少如果您希望它是通用的并接受任意用户输入。了解这些边缘案例往往更多地来自现实世界的经验,而不仅仅是快速浏览。不过,一旦您了解了它们,再次编写代码就不会非常困难,您知道要测试什么!但如果你不知道,你可以用数百个单元测试编写漂亮的代码......但是错过了真实世界的案例,你的用户只是碰巧尝试了一次这很重要。

使用std.csv

import std.csv;
import std.stdio;

void main()
{
    auto str = `foo,bar,"hello, user",baz`;

    foreach (row; csvReader(str))
    {
        writeln(row);
    }
}

应用程序输出:

["foo", "bar", "hello, user", "baz"]

请注意,我修改了您的 CSV 示例数据。由于 std.csv 无法正确解析它,因为 space (</code>) 在第一个引号 (<code>").

之前