【问题标题】:Parsing csv file with unknown delimiter symbol解析带有未知分隔符的csv文件
【发布时间】:2012-07-18 12:47:01
【问题描述】:

我必须编写(或使用现有的)csv 解析库。

问题是文件以不同的分隔符以不同的格式上传,例如:

File1:
field1; field2; field3; field4
field1; field2; field3; field4

File2:
feld1, field2, field3, field4
feld1, field2, field3, field4

File3:
"field1", "field2", "field3", "field4"
"field1", "field2", "field3", "field4"

以编程方式了解哪个符号是列的实际分隔符的最佳方法是什么?

我正在考虑编写自己的符号统计分析方法,但也许有现有的解决方案?

【问题讨论】:

    标签: .net parsing csv delimiter


    【解决方案1】:

    我会使用正则表达式(希望不会像上次那样得到尽可能多的反对票;))。我正在利用backreferences,它基本上允许使用以前捕获的组。只要每行使用相同的分隔符,您也可以在同一个文件中使用不同的分隔符(虽然不知道它是否有用)。

    所以,这就是我构建正则表达式的方式:

    string csvItem = @"[""']?\w+[""']?";
    string separator = @"\s*[,\.;-]\s*";
    string pattern = string.Format(@"^({0}(?<sep>{1}){0})+(\k<sep>{0})*$",
        csvItem, separator);
    

    csvItem 是 csv 中的一个项目(列)。它可以包含小写或大写字母、数字和下划线,并且可以选择用 " 或 ' 包围。

    分隔符分隔项目。它由这些字符之一,.;- 和零个或多个空格字符组成。

    该模式表示有效行由至少两个由分隔符分隔的 csvItems 组成。注意反向引用 -> \k

    来了。这是测试文件的内容:

    field1; field2; field3; field4
    field1; field2; field3; field4
    
    feld1, field2, field3, field4
    feld1, field2, field3, field4
    
    "field1", "field2", "field3", "field4"
    "field1", "field2", "field3", "field4"
    

    还有一个示例控制台项目:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace csvParser {
        class Program {
            static void Main( string[ ] args ) {
                var lines = File.ReadAllLines( @"e:\prova.csv" );
    
                for ( int i = 0; i < lines.Length; i++ ) {
                    string csvItem = @"[""']?\w+[""']?";
                    string separator = @"\s*[,\.;-]\s*";
                    string pattern = string.Format(@"^({0}(?<sep>{1}){0})+(\k<sep>{0})*$", csvItem, separator);
    
                    var rex = new Regex( pattern, RegexOptions.Singleline );
                    var match = rex.Match( lines[ i ] );
    
                    if ( match == null ) {
                        Console.WriteLine( "No match on line {0}", i );
                        continue;
                    }
                    else {
                        string sep = match.Groups[ "sep" ].Value;
    
                        Console.WriteLine( "--- Line #{0} ---------------", i );
                        Console.WriteLine( "Line is '{0}'", lines[ i ] );
                        Console.WriteLine( "Separator is '{0}'", sep );
    
                        Console.WriteLine( "Items are:" );
                        foreach ( string item in lines[ i ].Split( sep ) )
                            Console.WriteLine( "\t'{0}'", item );
    
                        Console.WriteLine( );
                    }
                }
    
                Console.ReadKey( );
            }
        }
    
        public static partial class Extension {
            public static string[ ] Split( this string str, string sep ) {
                return str.Split( new string[ ] { sep }, StringSplitOptions.RemoveEmptyEntries );
            }
        }
    }
    

    最后是它的输出:

    --- Line #0 ---------------
    Line is 'field1; field2; field3; field4'
    Separator is '; '
    Items are:
            'field1'
            'field2'
            'field3'
            'field4'
    
    --- Line #1 ---------------
    Line is 'field1; field2; field3; field4'
    Separator is '; '
    Items are:
            'field1'
            'field2'
            'field3'
            'field4'
    
    --- Line #2 ---------------
    Line is ''
    Separator is ''
    Items are:
    
    --- Line #3 ---------------
    Line is 'feld1, field2, field3, field4'
    Separator is ', '
    Items are:
            'feld1'
            'field2'
            'field3'
            'field4'
    
    --- Line #4 ---------------
    Line is 'feld1, field2, field3, field4'
    Separator is ', '
    Items are:
            'feld1'
            'field2'
            'field3'
            'field4'
    
    --- Line #5 ---------------
    Line is ''
    Separator is ''
    Items are:
    
    --- Line #6 ---------------
    Line is '"field1", "field2", "field3", "field4"'
    Separator is ', '
    Items are:
            '"field1"'
            '"field2"'
            '"field3"'
            '"field4"'
    
    --- Line #7 ---------------
    Line is '"field1", "field2", "field3", "field4"'
    Separator is ', '
    Items are:
            '"field1"'
            '"field2"'
            '"field3"'
            '"field4"'
    

    不幸的是,正则表达式也会捕获空行。正在尝试修复它:)

    【讨论】:

    • 谢谢,这真是太棒了!
    • 但是您的方法需要预定义的可能分隔符列表。我希望有一种方法可以计算给定文件的大多数可能分隔符。
    • @Ruslan:嗯,我认为这很难做到。您至少应该知道要查找的分隔符类型或它们包含的字符。
    • 当 csv 格式为双引号和空格时不起作用。
    猜你喜欢
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 2019-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多