2

我正在尝试匹配类似 CSV 文件中的所有新行。问题是巨大的文件总是带有一些断线,例如:

123|some string field|person 123|some optional open comment|324|213
133|some string field|person||324|213
153|some string field|person 123|some comment|324|213
126|some string field|another id|some open and
new line comment|324|213
153|string field|person 123|some comment|324|213
153|string field|person 123|another broken line
comment|324|213
133|field|person||324|213

因此,为了解决这种情况,我使用了以下逻辑:

    string ZSUR = File.ReadAllText(filePath);
    string originalFilePath = filePath;

    // Regular Expression to fix line break issues
    Regex RE = new Regex(@"[\r\t\n]+([^0-9\r\t\n]{3}[^|\r\t\n])");

    ZSUR = RE.Replace(ZSUR, "$1");

    // Backup the original file
    string[] backupFilePath = Regex.Split(filePath, @".txt$");
    File.Delete(backupFilePath[0] + "_BACKUP.txt");
    File.Move(originalFilePath, backupFilePath[0] + "_BACKUP.txt");

    // And then save on the same path the fixed file
    File.WriteAllText(originalFilePath, ZSUR);

它解决了 90% 的情况,因为正确行的第一部分总是以三位数开头,后跟一个竖线。

但我不知道为什么它与这样的情况不匹配:

126|some string field|another id|some open and
double newlined 
123 coment|324|213
153|some string field|person 123|some comment|324|213
153|some string field|person 123|some comment|324|213
153|string field|person 123|Please split this line
31 pcs: 05/03/2013
31|324|213
153|some string field|person 123|some comment|324|213

如您所见,我需要一种不同的方法来解决这个问题。我知道在 N 次之后我有一个管道,那个烦人的评论字段就在那里。那么,有什么方法可以匹配从一行开始的 N 个管道之后的所有新行和类似行吗?

也欢迎其他想法。

编辑:谢谢你们的回答。

我使用以下正则表达式解决了这个问题:

(?<!\|[CA]?\|([0-9]{2}.[0-9]{2}.[0-9]{4})?)[\n\r]+

当然,我的真实文件与发布的示例略有不同,但主要想法只是匹配所有新行 [\n\r]+ 之前没有

(?<! ... ) 

表达。

4

3 回答 3

1

您可以像这样处理所有内容,其中“清洁”是您定义的方法。

var prev = string.Empty;
const int requiredValueCount = 6;

foreach (var line in lines2.Split(new[] {Environment.NewLine}, StringSplitOptions.None))
{
    var values = (prev + line).Split('|');

    if (values.Length == requiredValueCount)
    {
        prev = string.Empty;
        Clean(values);
    }
    else
    {
        prev += line;
    }
}
于 2013-02-22T17:28:20.757 回答
0

首先将所有 (\|\d+\n) 替换为类似 \|\d~~

然后加入所有行,删除 \n

然后分开~~

于 2013-02-22T17:23:21.400 回答
0

我不会不必要地重新发明轮子。试试 Sebastien Lorion 的快速 CSV 阅读器。它可能会完成您需要做的事情(或为您提供对错误采取纠正措施的设施)。我用过这个阅读器,它非常好。

另一种选择是来自 Codeplex的KBCsv 。没用过,不过应该不错

我还将采取将文件按原样读取到记录列表中的方法。由于您似乎不需要多于一点的前瞻/后视,因此您可以在文件的单次传递中轻松完成,如下所示:

public IEnumerable<string[]> ReadRecordsFromCSV()
{
  string[] prev = null ;
  string[] curr = null ;

  // read each individual record from the file
  while ( null != (curr=MyCsvReader.ReadRecord()) )
  {

    if ( prev == null )
    { // no previous record? just shift and continue
      prev = curr ;
    }
    else
    { // previous record? splice if needed and emit a record
      string[] record ;
      bool spliceNeeded = CheckForSpliceConditions(prev,curr) ;

      if ( spliceNeeded )
      { // splice needed? build the record to emit and clear the previous record
        record = Splice( prev , curr ) ;
        prev = null ;
      }
      else
      { // no splice needed? set the record to emit and shift
        record = prev ;
        prev = curr ;
      }

    }

    // emit the record
    yield return record ;
  }

  // emit the last record if there is one.
  if ( prev != null )
  {
    yield return prev ;
  }

}

如果您需要多于一级的前瞻/后视,则需要移位寄存器之类的东西,您可以在其中将记录添加到列表的末尾并从列表的开头删除它们。您可以使用 aList<string[]>作为这样的移位寄存器,尽管这样做有点难看。

编辑注意:或者(更简单),如果需要拼接,只需将当前记录附加到前一个记录,直到不再需要拼接。一旦这是真的,之前的记录就会被发出,你会从一个干净的状态重新开始,因此:

public IEnumerable<string[]> ReadRecordsFromCSV()
{
  string[] prev = null ;
  string[] curr = null ;

  // read each individual record from the file
  while ( null != (curr=MyCsvReader.ReadRecord()) )
  {

    if ( prev == null )
    { // no previous record? just shift and continue
      prev = curr ;
    }
    else
    { // previous record? splice if needed and emit a record
      bool spliceNeeded = CheckForSpliceConditions(prev,curr) ;

      if ( spliceNeeded )
      { // splice needed? build the record to emit and clear the previous record
        prev = Splice( prev , curr ) ;
      }
      else
      { // no splice needed? set the record to emit and shift
        yield return prev ;
        prev = null ;
      }

    }

  }

  // emit the last record if there is one.
  if ( prev != null )
  {
    yield return prev ;
  }

}
于 2013-02-22T18:59:56.363 回答