每次解析一个字符时识别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-rslash-n都不会输出到控制台,在调试期间也不会命中它们。实际上,这里写入控制台的唯一输出是文本"Done!"。

每次解析一个字符时识别StringReader中的换行符

如果其他人遇到这个特定的问题(因为我在问问题之前找不到关于它的具体答案),结果是对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