Ton*_*zzo 8 c# newline readline streamreader
我写了一个C#程序来读取Excel .xls/.xlsx文件并输出到CSV和Unicode文本.我写了一个单独的程序来删除空白记录.这是通过读取每一行来完成的StreamReader.ReadLine(),然后通过字符串逐个字符地进行,如果它包含所有逗号(对于CSV)或所有选项卡(对于Unicode文本),则不将该行写入输出.
当Excel文件在单元格内包含嵌入的换行符(\ x0A)时,会发生此问题.我将我的XLS更改为CSV转换器以找到这些新行(因为它逐个单元格)并将它们写为\ x0A,而普通行只使用StreamWriter.WriteLine().
在单独的程序中发生问题以删除空白记录.当我读入时StreamReader.ReadLine(),根据定义它只返回带有行的字符串,而不是终止符.由于嵌入的换行符显示为两个单独的行,我无法分辨哪个是完整记录,哪个是我将它们写入最终文件时的嵌入式换行符.
我甚至不确定我能读到\ x0A,因为输入上的所有内容都注册为'\n'.我可以逐字逐句,但这会破坏我删除空行的逻辑.
Sco*_*ski 13
我建议您将架构更改为更像编译器中的解析器.
您想要创建一个返回标记序列的词法分析器,然后创建一个解析标记序列并使用它们完成任务的解析器.
在你的情况下,令牌将是:
您可以将'\n'('\ x0a')作为嵌入的新行处理,因此将其作为列数据标记的一部分包含在内.'\ r \n'将构成行尾令牌.
这具有以下优点:
以下是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;
}
Run Code Online (Sandbox Code Playgroud)
您的"解析器"代码将如下所示:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
24185 次 |
| 最近记录: |