当前位置:  开发笔记 > 编程语言 > 正文

需要使用StreamReader.ReadLine()获取行终止符

如何解决《需要使用StreamReader.ReadLine()获取行终止符》经验,为你挑选了1个好方法。

我写了一个C#程序来读取Excel .xls/.xlsx文件并输出到CSV和Unicode文本.我写了一个单独的程序来删除空白记录.这是通过读取每一行来完成的StreamReader.ReadLine(),然后通过字符串逐个字符地进行,如果它包含所有逗号(对于CSV)或所有选项卡(对于Unicode文本),则不将该行写入输出.

当Excel文件在单元格内包含嵌入的换行符(\ x0A)时,会发生此问题.我将我的XLS更改为CSV转换器以找到这些新行(因为它逐个单元格)并将它们写为\ x0A,而普通行只使用StreamWriter.WriteLine().

在单独的程序中发生问题以删除空白记录.当我读入时StreamReader.ReadLine(),根据定义它只返回带有行的字符串,而不是终止符.由于嵌入的换行符显示为两个单独的行,我无法分辨哪个是完整记录,哪个是我将它们写入最终文件时的嵌入式换行符.

我甚至不确定我能读到\ x0A,因为输入上的所有内容都注册为'\n'.我可以逐字逐句,但这会破坏我删除空行的逻辑.



1> Scott Wisnie..:

我建议您将架构更改为更像编译器中的解析器.

您想要创建一个返回标记序列的词法分析器,然后创建一个解析标记序列并使用它们完成任务的解析器.

在你的情况下,令牌将是:

    列数据

    逗号

    行结束

您可以将'\n'('\ x0a')作为嵌入的新行处理,因此将其作为列数据标记的一部分包含在内.'\ r \n'将构成行尾令牌.

这具有以下优点:

    只对数据进行一次传递

    仅存储最多1行的数据

    尽可能多地重用内存(对于字符串生成器和列表)

    如果您的要求发生变化,很容易改变

以下是Lexer的样子:

免责声明:我甚至没有编译,更不用说测试这个代码了,所以你需要清理它并确保它有效.

enum TokenType
{
    ColumnData,
    Comma,
    LineTerminator
}

class Token
{
    public TokenType Type { get; private set;}
    public string Data { get; private set;}

    public Token(TokenType type)
    {
        Type = type;
    }

    public Token(TokenType type, string data)
    {
        Type = type;
        Data = data;
    }
}

private  IEnumerable GetTokens(TextReader s)
{
   var builder = new StringBuilder();

   while (s.Peek() >= 0)
   {
       var c = (char)s.Read();
       switch (c)
       {
           case ',':
           {
               if (builder.Length > 0)
               {
                   yield return new Token(TokenType.ColumnData, ExtractText(builder));
               }
               yield return new Token(TokenType.Comma);
               break;
           }
           case '\r':
           {
                var next = s.Peek();
                if (next == '\n')
                {
                    s.Read();
                }

                if (builder.Length > 0)
                {
                    yield return new Token(TokenType.ColumnData, ExtractText(builder));
                }
                yield return new Token(TokenType.LineTerminator);
                break;
           }
           default:
               builder.Append(c);
               break;
       }

   }

   s.Read();

   if (builder.Length > 0)
   {
       yield return new Token(TokenType.ColumnData, ExtractText(builder));
   }
}

private string ExtractText(StringBuilder b)
{
    var ret = b.ToString();
    b.Remove(0, b.Length);
    return ret;
}

您的"解析器"代码将如下所示:

public void ConvertXLS(TextReader s)
{
    var columnData = new List();
    bool lastWasColumnData = false;
    bool seenAnyData = false;

    foreach (var token in GetTokens(s))
    {
        switch (token.Type)
        {
            case TokenType.ColumnData:
            {
                 seenAnyData = true;
                 if (lastWasColumnData)
                 {
                     //TODO: do some error reporting
                 }
                 else
                 {
                     lastWasColumnData = true;
                     columnData.Add(token.Data);
                 }
                 break;
            }
            case TokenType.Comma:
            {
                if (!lastWasColumnData)
                {
                    columnData.Add(null);
                }
                lastWasColumnData = false;
                break;
            }
            case TokenType.LineTerminator:
            {
                if (seenAnyData)
                {
                    OutputLine(lastWasColumnData);
                }
                seenAnyData = false;
                lastWasColumnData = false;
                columnData.Clear();
            }
        }
    }

    if (seenAnyData)
    {
        OutputLine(columnData);
    }
}

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有