我正在研究使用MS堆栈(包括.NET)进行分隔文件(例如CSV,制表符分隔等)解析的选项。由于我已经知道SSIS无法满足我的需求,因此我排除了它。
所以我的选择似乎是:
- Regex.Split
- TextFieldParser
- OLEDB CSV Parser
我必须满足两个标准。第一个标准是在下面文件中,必须产生两个逻辑“行”,每个行都由三个字符串(或列)组成。第三个行/列字符串必须保留换行符!换句话说,解析器必须识别哪些行由于“未关闭”的文本限定符而“继续”到下一行:
101,Bob,“保持他的房子干净。
需要处理洗衣。”
102,Amy,“聪明。
积极进取。
勤奋。”
第二个标准是分隔符和文本限定符必须是可配置的。这是来自不同文件的两个字符串,我必须能够解析它们:
var first = @"""This"",""Is,A,Record"",""That """"Cannot"""", they say,"","""",,""be"",rightly,""parsed"",at all";
var second = @"~This~|~Is|A|Record~|~ThatCannot~|~be~|~parsed~|at all";
对字符串 "first" 的正确解析应该是:
- This
- Is,A,Record
- That "Cannot", they say,
- _
- _
- be
- rightly
- parsed
- at all
下划线 '_' 只是表示捕获了一个空格 - 我不希望出现字面上的下划线。
关于要解析的平面文件,可以做出一个重要的假设:每个文件中将有固定数量的列。
现在进入技术选项的深入探讨。
正则表达式
首先,许多回答者评论说正则表达式“不是实现目标的最佳方法”。但是,我找到了一位评论者提供的优秀的 CSV 正则表达式:
var regex = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";
var Regex.Split(first, regex).Dump();
应用于字符串 "first" 的结果非常好:
- "This"
- "Is,A,Record"
- "That ""Cannot"", they say,"
- ""
- _
- "be"
- 正确地
- "parsed"
- 全部都不能被
希望引号可以被清理干净,但我可以轻松地在后处理步骤中处理。否则,只要将正则表达式针对波浪符和管道符号进行修改,此方法就可用于解析样本字符串“first”和“second”。太棒了!
但真正的问题与多行条件有关。在将正则表达式应用于字符串之前,我必须从文件中读取完整的逻辑“行”。不幸的是,除非我有一个正则表达式/状态机,否则我不知道要读取多少物理行才能完成逻辑行。
所以这成为了一个“先有鸡还是先有蛋”的问题。我的最佳选择是将整个文件读入内存作为一个巨大的字符串,让正则表达式处理多行(我没有检查以上正则表达式是否能够处理这种情况)。如果我有一个10GB的文件,这可能有些危险。
接下来是另一个选项。
TextFieldParser
只需三行代码,就可以发现此选项的问题:
var reader = new Microsoft.VisualBasic.FileIO.TextFieldParser(stream);
reader.Delimiters = new string[] { @"|" };
reader.HasFieldsEnclosedInQuotes = true;
分隔符配置看起来不错。但是,"HasFieldsEnclosedInQuotes"则是"game over"。我很震惊分隔符可以任意配置,但与此形成对比的是,除了引号,我没有其他限定符选项。记住,我需要可配置文本限定符。所以,除非有人知道TextFieldParser配置技巧,否则这就是个失败的尝试。
OLEDB
一位同事告诉我,这个选项有两个主要缺陷。首先,对于大型文件(例如10GB),性能很差。其次,据我所知,它猜测输入数据的数据类型而不是让您自行指定。这样不好。
HELP
因此,如果我有任何错误的理解,请告诉我正确的情况,以及我可能遗漏的其他选项。也许有人知道如何强制TextFieldParser使用任意分隔符。也许OLEDB已经解决了所述问题(或者从未有过?)。
你怎么看?