фильтрация потоков в c # - PullRequest
1 голос
/ 15 июня 2009

Какой самый простой способ построчно фильтровать поток / читатель в c # (что-то вроде размещения sed в середине конвейера). Я хочу передать файл iCalendar в DDay.iCal, но DDay.iCal умирает при "VERSION: 5.1.1", потому что ему нужен номер или номер SEMICOLON number (где number это цифры (DOT цифры)? Так что последний "." неожиданный).

Я хочу отфильтровать строку VERSION: к чему-то безобидному, например, "VERSION: 5.1", чтобы анализатор не умер.

Обновление: Хорошо, вот пример:

BEGIN:VCALENDAR
PRODID:-//SunONE/Calendar Hosting Server//EN
METHOD:PUBLISH
VERSION:5.1.1
X-NSCP-CALPROPS-LAST-MODIFIED:20011208T005613Z
X-NSCP-CALPROPS-CREATED:20010913T223336Z
X-NSCP-CALPROPS-READ:999
X-NSCP-CALPROPS-WRITE:999

Теперь парсер DDay.iCal не любит "VERSION: 5.1.1", поэтому я хочу заменить его чем-то безобидным, как "VERSION: 5.1".

Интерфейс парсера принимает ридер или поток.

В любом случае, я пытался использовать код здесь , и он работает (переопределение TextReader поверх отфильтрованной ReadLine).

Ответы [ 2 ]

7 голосов
/ 15 июня 2009

System.IO.Stream использует шаблон декоратора, поэтому он довольно легко позволяет создать собственный, который оборачивает основной поток. Это позволяет таким потокам, как CryptoStream и GZipStream, обернуть любой другой экземпляр Stream и эффективно «переопределить» его методы чтения / записи, не выходя из класса, который вы хотите расширить. Очень гибкий и популярный шаблон дизайна, описанный в книге «Банды четырех».

Теперь я не уверен, требует ли API, с которым вы работаете, Stream или StreamReader. Существует значительное различие между ними. StreamReader работает на уровне text и работает с символами / строками. Поток работает на двоичном уровне и работает с байтами. Другими словами, ожидается, что StreamReader сможет декодировать байты в текст, чтобы потребителю не нужно было беспокоиться о кодировке. Используйте Stream, если кодирование не имеет значения (например, при сжатии или кодировании), и используйте StreamReader при работе с текстовыми данными.

Судя по тому, как это звучит, StreamReader будет иметь больше смысла. Если API может принимать StreamReader, просто извлеките свой собственный из TextReader и переопределите его метод ReadLine, чтобы первый вызов возвращал строку текста, к которой вы хотите добавить, а последующие вызовы просто функционируют как обычно.

Другой вариант - просто использовать StringWriter / StringReader и поместить все это в строковый буфер в памяти, манипулировать им, а затем передавать его.

5 голосов
/ 15 июня 2009

Самый простой способ - обернуть поток в IEnumerable и отфильтровать его с помощью LINQ:

static void Main(string[] args)
{
    System.IO.StreamReader sr = // ...
    var filtered = Enumerable.Where(
        StreamReaderToSeq(sr), input => { int temp; return int.TryParse(x, out temp); });
}

static IEnumerable<string> StreamReaderToSeq(System.IO.StreamReader sr)
{
    while(!sr.EndOfStream)
    {
        yield return sr.ReadLine();
    }
}

Приведенная выше последовательность фильтрует только целые числа, но достаточно просто написать лучший фильтр для обработки всех требуемых входных данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...