什么是在C#中解析此文件的方法,其中我在一个字段内有一个CRLF

时间:2010-07-12 01:04:08

标签: c# parsing

我正在尝试解析一个看起来像这样的文件:

  

||列标题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行(因为最后一行显示为该数组中的两个条目。)

6 个答案:

答案 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));