每次解析一个字符时识别StringReader中的换行符
本文关键字:识别 字符 StringReader 换行符 一个 | 更新日期: 2023-09-27 18:17:39
我正在解析一个文本文件并对其进行标记以供以后处理。程序使用File.ReadAllText()
将整个文本文件读入内存,然后将整个字符串传递给标记器。标记器将文本放入StringReader
中,然后每次处理一个字符。
现在,只要出现不匹配,它就会生成一个基本的语法错误,但是我想包括发生错误的行号。当使用StringReader
逐个字符处理字符串时,是否有可能识别'r'n
序列?因为我在case语句中包含了检查,以显式地查找''r'和''n',并且在调试期间两个分支都没有触发。除以下字符外,所有其他字符都匹配。
示例代码:(完整上下文的简化版本见下文)
var c = (char)_reader.Peek();
switch(c)
{
... bunch of case statements here ...
case '"':
ParseStringToken();
break;
case ',':
ParseCommaToken();
break;
case '.':
ParseFullStopToken();
break;
case ''r':
ParseEndOfLineToken();
break;
case ''n':
ParseEndOfLineToken();
break;
... more case statements ...
}
示例中的最后一个分支永远不会触发。我也试过识别'n
,它也从不开火。由于Environment.NewLine
是一个包含两个字符的字符串,似乎它在这里不起作用,因为我只提前Peek
一个字符。除非答案是在default
情况下的if
语句中包含两个字符的Peek
,以捕获这种情况?
似乎必须有一种方法来识别行结束符。我错过了什么?谢谢。
编辑为了回应Steve,我简化了标记器:
public class Tokenizer
{
private readonly StringReader _reader;
private List<Token> _tokens;
public Tokenizer(string text)
{
_reader = new StringReader(text);
_tokens = new List<Token>();
}
public IEnumerable<Token> Tokenize()
{
while (_reader.Peek() > -1)
{
while (Char.IsWhiteSpace((char)_reader.Peek()))
_reader.Read();
if (-1 == _reader.Peek())
break;
var c = (char)_reader.Peek();
switch(c)
{
case ''n':
Console.WriteLine("slash-n");
_reader.Read();
break;
case ''r':
Console.WriteLine("slash-r");
_reader.Read();
break;
default:
_reader.Read();
break;
}
}
return _tokens;
}
}
这里是调用代码,它现在只是一个控制台应用程序的Main
方法:
static void Main(string[] args)
{
var path = @"source.txt";
var text = File.ReadAllText(path);
var tokenizer = new Tokenizer(text);
var tokens = tokenizer.Tokenize();
Console.WriteLine(String.Join("'n", tokens));
Console.WriteLine();
Console.WriteLine("Done!");
Console.ReadKey();
}
slash-r
和slash-n
都不会输出到控制台,在调试期间也不会命中它们。实际上,这里写入控制台的唯一输出是文本"Done!"。
如果其他人遇到这个特定的问题(因为我在问问题之前找不到关于它的具体答案),结果是对Char.IsWhitespace()
的调用对于行尾字符'r
和'n
都返回true。我愚蠢地忘记了这一点。
因为我需要绕过空格,但想要捕获这些字符,为了解决这个问题,我只是创建了我自己的私有方法来包装它,并为这两个字符中的任何一个返回false。
private bool IsWhitespace(char c)
{
return (''n' != c && ''r' != c && Char.IsWhiteSpace(c));
}
在标记器的循环中,我替换了对Char.IsWhitespace
的调用:
while (IsWhitespace((char)_reader.Peek()))
_reader.Read();
现在它分别正确地触发这两个EOL字符。因此,为EOL序列编写解析函数是微不足道的,一旦检测到'r
,它将消耗它和下一个字符'n
,并正确地发出EndOfLineToken
。