我正在尝试解析一个看起来像这样的文件:
||列标题A ||列标题B ||列标题C || CRLF
|数据A |数据B |数据C | CRLF
|数据A |数据B |数据C | CRLF
(“ CRLF ”表示换行符)
我有解析这个问题的代码:
我首先将文件解析为一个行数组:
string[] lines = fileString.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
然后,我将每一行解析为一组列数据值
首先,我解析使用标题来获取标题:
string Delimiter = "||";
string[] columns = line.Split(new string[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
然后使用
解析其余行 string Delimiter = "|";
string[] columns = line.Split(new string[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
这种方法很有效,直到我发现一个字段内有 CRLF 的记录,所以我的解析分解了。
有人能想出一种解析下面这些数据的好方法,并正确处理 CRLF 吗?这是一个例子:
||列标题A ||列标题B ||列标题C || CRLF
|数据A |数据B |数据C | CRLF
|数据A |数据B CRLF 续B |数据C | CRLF
问题在于,当我进行初始解析以获取行数时,我在这里得到4行而不是3行(因为最后一行显示为该数组中的两个条目。)
答案 0 :(得分:3)
这里有你的分隔文字。 String.Split()是解析这类数据的一个众所周知的天真选择。它很慢,容易出现诸如你现在所经历的问题。更好的解决方案类似于Microsoft.VisualBasic.TextFieldParser
类或Fast CSV parser over on codeproject。
答案 1 :(得分:2)
不完全优雅,但这首暴力解决方案是第一个想到的。拆分,然后合并,如果短:
var lines = content.Split(...);
string header[] = lines[0].Split(...);
int numberOfColumns = header.Length;
var parsedLines = new List<string[]>();
for (int i = 1; i < lines.Length; i++) {
var line = lines[i];
while ((fields = line.Split(...)).Length < numberOfColumns) {
// combine with next, and increment i
line += lines[++i];
}
parsedLines.Add(fields);
}
答案 2 :(得分:1)
在这种情况下有一个简单的解决方法:
抓一条线。它以|?结尾吗?如果没有,请添加CRLF并将下一行添加到其中。重复,直到它以|结尾,然后解析它。
答案 3 :(得分:0)
根据您在问题中显示的内容,只是想法和想法:
删除在|之后没有出现的所有 CRLF 或||让最后一个出现(标记换行符)。这样做我认为您当前的代码仍然可以按照您想要的方式运行。
这样的事情:
string wrongLine = "| Data A | Data B \r\n Continued B | Data C |\r\n";
string rightLine = wrongLine.Replace(" " + Environment.NewLine, string.Empty);
它会给你这个输出(保持最后一个CRLF):
"| Data A | Data B Continued B | Data C |\r\n"
答案 4 :(得分:0)
这是Bad Data的典型示例,或者是分隔符的错误选择。在编写解析器之前,您必须100%确定代码所期望的数据。
在这种情况下,您在数据中遇到了CRLF,您(或您的代码)如何知道它实际上不是分隔符?
如果您有选择,我会说使用更好的分隔符。
编辑: 您需要在分隔符上了解发件人,然后由发件人负责确保数据质量。
查看您的示例数据,'| CRLF'似乎是一个很好的分隔符,而不是'CRLF'。但是你如何(解析器)确保在实际数据中没有出现这个分隔符?你不能。您可以做的是根据与发送方达成的模式验证数据的质量(例如,记录中的列数等)。如果验证失败,请将错误报告给发件人并要求重新发送。
更好的方法是让发件人给你一个包含数据详细信息的标题(即没有记录,没有列等)。
作为解析器,您对数据的控制是有限的。此问题需要发件人的支持。
答案 5 :(得分:-1)
您应该考虑使用CSV解析库。
但是,你可以做一些像这样的事情(比最好的情况更多的概念验证),如果你真的反对这条道路并且可以保证你的列标题没有杂项CRLF
string Delimiter = "||";
string[] columns = fileString.Substring(0, fileString.IndexOf(Environment.NewLine))
.Split(new string[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
string[] cells = fileString.Substring(fileString.IndexOf(Environment.NewLine))
.Split(new string[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
List<string> rows = new List<string>();
StringBuilder row = new StringBuilder();
int colIndex = 0;
int breakIndex = columns.Length;
char[] trimChars = new char[] { '\r','\n',' ' };
foreach(string c in cells)
{
if (cellIndex == breakIndex)
{
rows.Add(row.ToString().Trim(trimChars));
cellIndex = 0;
row = new StringBuilder();
}
row.Append(c).Append(" ");
cellIndex ++;
}
rows.Add(row.ToString().Trim(trimChars));