Я создаю собственное средство чтения ввода для синтаксического анализатора на С# и пытаюсь получить n-й символ из средства чтения потока, не перемещая позицию потока, чтобы при многократном вызове функции я получал один и тот же вывод (например, встроенная функция просмотра).
В настоящее время я могу получить n-й элемент, как показано в коде ниже, однако при этом я перемещаю позицию потоков, и поэтому при каждом вызове я получаю другой символ.
private StreamReader _reader;
private int _peekChar = -1;
public InputReader(Stream inputStream)
{
_reader = new StreamReader(inputStream);
}
// Returns the next character in the input stream without consuming it
public char Peek()
{
// Checks if character already peeked
if (_peekChar == -1)
_peekChar = _reader.Peek();
return (char)_peekChar;
}
// Returns the n th next character in the input stream without consuming it
public char Peek(int n)
{
if (n <= 0)
throw new ArgumentException("n must be a positive integer.");
char[] buffer = new char[n];
int bytesRead = _reader.Read(buffer, 0, n);
if (bytesRead < n)
throw new EndOfStreamException("Not enough characters in the stream to peek.");
return buffer[n - 1];
}
Учитывая, что я вызываю Peek(1) 3 раза в потоке с "<HTML> <p> test <p/> <HTML/>"
, я ожидаю 3 вывода <
, однако получаю <
H
T
🤔 А знаете ли вы, что...
C# является статически типизированным языком, что обеспечивает высокую безопасность и производительность кода.
Когда ты
_reader.Read(buffer, 0, n);
Затем позиция потока увеличивается.
Вам нужно переместить позицию потока обратно после чтения (если поток это поддерживает)
_reader.Seek(-bytesRead, SeekOrigin.End);
В этой ситуации я бы написал «PeekableStream», который поддерживает буфер, в который вы можете заглянуть. Он будет извлекать символы из буфера, если он доступен, а затем из исходного потока, когда буфер исчерпан. Буфер расширяется и заполняется на основе числа «n», переданного методу Peek.
Основываясь на ответе, предоставленном divinci, я обновил свою функцию до
public char Peek(int n)
{
if (n < 0)
throw new ArgumentException("k must be a positive integer.");
long originalPosition = _reader.BaseStream.Position;
char[] buffer = new char[n + 1];
// Read characters up to the n-th position
int readChars = _reader.Read(buffer, 0, n + 1);
_reader.BaseStream.Seek(originalPosition, SeekOrigin.Begin);
_reader.DiscardBufferedData();
if (readChars < n + 1)
throw new EndOfStreamException("Not enough characters in the stream to peek.");
return buffer[n];
}
Затем у меня возникла проблема с возможностью циклического выполнения функции, и я обнаружил, что всякий раз, когда я использовал _reader.Peek()
, она меняла положение потока. Я решил это, используя
long originalPosition = _reader.BaseStream.Position;
int nextChar = _reader.Peek();
_reader.BaseStream.Seek(originalPosition, SeekOrigin.Begin);
когда бы я ни позвонил _reader.Peek()