【问题标题】:regex to split line (csv file)正则表达式分割线(csv文件)
【发布时间】:2011-03-17 03:59:40
【问题描述】:

我不擅长正则表达式。有人可以帮我写正则表达式吗?

我在读取 csv 文件时可能会有这样的值。

“艺术家,名字”,专辑,12-SCS "val""u,e1",value2,value3

输出:

艺术家,姓名 专辑 12-SCS 值"u,e1 价值2 价值3

更新: 我喜欢使用 Oledb 提供程序的想法。我们确实在网页上有文件上传控制,我使用流阅读器读取文件的内容,而没有在文件系统上实际保存文件。有什么办法可以使用 Oledb 提供程序,因为我们需要在连接字符串中指定文件名,而在我的情况下,我没有文件保存在文件系统上。

【问题讨论】:

标签: c# .net regex csv


【解决方案1】:

试试CsvHelper(我维护的一个库)。它可以通过 NuGet 获得。

您可以轻松地将 CSV 文件读入自定义类集合。它也非常快。

var streamReader = // Create a StreamReader to your CSV file
var csvReader = new CsvReader( streamReader );
var myObjects = csvReader.GetRecords<MyObject>();

【讨论】:

    【解决方案2】:

    可以使用以下代码完成:

    using Microsoft.VisualBasic.FileIO;
    string csv = "1,2,3,"4,3","a,"b",c",end";
    TextFieldParser parser = new TextFieldParser(new StringReader(csv));
    //To read from file
    //TextFieldParser parser = new TextFieldParser("csvfile.csv");
    parser.HasFieldsEnclosedInQuotes = true;
    parser.SetDelimiters(",");
    string[] fields =null;
    while (!parser.EndOfData)
    {
        fields = parser.ReadFields();
    }
    parser.Close();
    

    【讨论】:

      【解决方案3】:

      刚刚添加了我今天早上工作的解决方案。

      var regex = new Regex("(?<=^|,)(\"(?:[^\"]|\"\")*\"|[^,]*)");
      
      foreach (Match m in regex.Matches("<-- input line -->"))
      {
          var s = m.Value; 
      }
      

      如您所见,您需要每行调用 regex.Matches()。然后它将返回一个 MatchCollection,其中包含与列相同数量的项目。每个匹配项的 Value 属性显然是解析后的值。

      这仍在进行中,但它可以愉快地解析 CSV 字符串,例如:

      2,3.03,"Hello, my name is ""Joshua""",A,B,C,,,D
      

      【讨论】:

      • 不幸的是,该正则表达式不匹配带有单个双引号的字段,例如field1,"""",field2
      • 用引号括起来的字段中间有一个换行符怎么样?
      【解决方案4】:

      实际上,用正则表达式匹配 CVS 行非常容易。试试这个:

      StringCollection resultList = new StringCollection();
      try {
          Regex pattern = new Regex(@"
              # Parse CVS line. Capture next value in named group: 'val'
              \s*                      # Ignore leading whitespace.
              (?:                      # Group of value alternatives.
                ""                     # Either a double quoted string,
                (?<val>                # Capture contents between quotes.
                  [^""]*(""""[^""]*)*  # Zero or more non-quotes, allowing 
                )                      # doubled "" quotes within string.
                ""\s*                  # Ignore whitespace following quote.
              |  (?<val>[^,]*)         # Or... zero or more non-commas.
              )                        # End value alternatives group.
              (?:,|$)                  # Match end is comma or EOS", 
              RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
          Match matchResult = pattern.Match(subjectString);
          while (matchResult.Success) {
              resultList.Add(matchResult.Groups["val"].Value);
              matchResult = matchResult.NextMatch();
          } 
      } catch (ArgumentException ex) {
          // Syntax error in the regular expression
      }
      

      免责声明: 正则表达式已在RegexBuddy(生成此 sn-p)中进行了测试,并且与 OP 测试数据正确匹配,但 C# 代码逻辑未经测试。 (我无权使用 C# 工具。)

      【讨论】:

      【解决方案5】:

      看看TextFieldParser 类。它位于 Microsoft.VisualBasic 程序集中,并进行定界和固定宽度解析。

      【讨论】:

      • +1 用于 TextFieldParser。它是 .NET 的隐藏瑰宝之一 - 可能是因为某种原因它隐藏在 VisualBasic 命名空间中。 (P.S.总是听从 Brian S 的建议。那些家伙真的很聪明!)
      【解决方案6】:

      Regex 不适合做这件事。使用 CSV 解析器builtin3rd party 之一。

      【讨论】:

      • 同意,正则表达式是错误的工具。我在 Codeproject 上使用了您链接到的 CsvReader,发现它非常适合处理 csv 文件。
      • 我喜欢使用 Oledb 提供程序的想法。我们确实在网页上有文件上传控制,我使用流阅读器读取文件的内容,而没有在文件系统上实际保存文件。有什么方法可以使用 Oledb 提供程序,因为我们需要在连接字符串中指定文件名,而在我的情况下,我没有文件保存在文件系统上。
      • 这是一个新问题。尝试用正确的标题、上下文和标签提出一个新的问题。
      • 内置的强制您将值转换为 .NET 类型。如果它猜错一列,它将丢失数据。第 3 方有很多错误。第 3 方代码中的CsvReader 类有 2500 行长,并且有很多写得不好的函数,所以调试也是一件苦差事。玩得开心!
      • +1 但是,您为什么不在 OSS 主机上发布那个漂亮的正则表达式库(例如 github、google 代码)。没有 CodeProject 帐户,我无法下载源代码。
      【解决方案7】:

      Regex 在这里可能会变得过于复杂。用逗号分割行,然后遍历结果位并将它们连接起来,其中“连接字符串中双引号的数量”不均匀。

      "你好,这个",is,"一个""测试"""

      ...拆分...

      “你好|这个”|是| “一个”“测试”“”

      ...迭代并合并'直到双引号的数量为偶数...

      "hello,this" - 偶数个引号(注意逗号通过插入位之间的拆分删除)

      是 - 偶数个引号

      "a ""test""" - 偶数个引号

      ...然后去掉前导和尾随引号(如果存在)并将 "" 替换为 ".

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-12
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多