gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 18:12:59 24 4
gpt4 key购买 nike

我编写了一个 C# 程序来读取 Excel .xls/.xlsx 文件并输出为 CSV 和 Unicode 文本。我写了一个单独的程序来删除空白记录。这是通过使用 StreamReader.ReadLine() 读取每一行,然后逐个字符地遍历字符串而不将包含所有逗号(对于 CSV)或所有制表符的行写入输出来实现的(对于 Unicode 文本)。

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

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

我什至不确定我是否可以读取\x0A,因为输入寄存器中的所有内容都为“\n”。我可以逐字逐句,但这破坏了我删除空行的逻辑。

最佳答案

我建议您更改架构,使其更像编译器中的解析器。

您想创建一个返回标记序列的词法分析器,然后创建一个读取标记序列并对其进行处理的解析器。

在您的情况下, token 将是:

  1. 列数据
  2. 逗号
  3. 行尾

您会将 '\n' ('\x0a') 本身视为嵌入的新行,因此将其作为列数据标记的一部分包含在内。 '\r\n' 将构成行尾标记。

这样做的好处是:

  1. 只传递 1 次数据
  2. 最多只存储 1 行数据
  3. 尽可能多地重复使用内存(用于字符串生成器和列表)
  4. 如果您的要求发生变化,它很容易改变

下面是 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<Token> 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<string>();
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);
}
}

关于c# - 需要使用 StreamReader.ReadLine() 获取行终止符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/667771/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com