私はテキストファイルを解析し、後で処理するためにそれをトークン化しています。プログラムは、File.ReadAllText()
を使用してテキストファイル全体をメモリに読み込んだ後、文字列全体をトークナイザに渡します。トークナイザは、テキストをStringReader
に配置し、一度に1文字ずつ処理します。一度に1つの文字を解析するときにStringReader内の改行文字を認識
現在は、不一致が発生するたびに基本的な構文エラーが生成されますが、エラーが発生した行番号を含めることにします。 StringReader
を使用してchar-by-char文字列を処理するときに、\r\n
シーケンスを認識できますか?なぜなら、明示的に '\ r'と '\ n'の両方を探すために私のcase文にチェックを入れていて、どちらのブランチもデバッグ中に起動しないからです。それ以外の文字はすべて一致します。
コード例:(フルコンテキストで簡略化されたバージョンについては下記を参照)
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
は2つの文字を含む文字列なので、ここではうまくいきません。なぜなら、私はPeek
先に1文字だけ先送りしているからです。答えがdefault
ケースのif
の文に2文字のPeek
を含めるのでなければ、この状況を捕まえることができますか?
行末の文字を認識する方法が必要なようです。私は何が欠けていますか?ありがとう。スティーブに対応して
編集私はトークナイザを簡素化:
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で進めるようにストリームの位置をどのようにインクリメントしますか? – Steve
ところで、私はあなたの問題を再現できません。あなたはすべてのスイッチケースをコメントアウトしようとしましたが、改行に関連する2つのものと、デバッガで何が起こるかを見ましたか? – Steve
@スティーブこれは大きなメソッド内のスニペットです。ストリームは 'Parse * Token'メソッド呼び出しで適切な数の' Read() '呼び出しによって進められます。だから、 'ParseCommaToken'は' Read() 'を一度呼び出すのに対し、' ParseStringToken'は閉じダブルクォートに達するまで 'Read()'を行います。希望は意味をなさない。 – Dave