filtering streams in c#

我只是一个虾纸丫 提交于 2019-12-24 07:18:12

问题


What's the easiest way to filter a stream/reader line-by-line in c# (somewhat like putting sed in the middle of a pipeline). I want to feed an iCalendar file to DDay.iCal but DDay.iCal dies on "VERSION:5.1.1" because it wants a number or number SEMICOLON number (where number is digits (DOT digits)? so the last "." is unexpected).

What I want to do is filter the VERSION: line to something harmless like "VERSION:5.1" so the parser doesn't die.

Update: OK, here's a sample:

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

Now, the DDay.iCal parser doesn't like "VERSION:5.1.1", so I want to replace that with something harmless like "VERSION:5.1".

The parser interface takes a reader or a stream.

Anyway, I tried to use the code here and it works (reimplementing TextReader on top of a filtered ReadLine).


回答1:


System.IO.Stream uses the decorator pattern so it makes it pretty easy to create your own which wraps an underlying stream. This allows streams such as CryptoStream and GZipStream to wrap any other Stream instance and effectively "override" its Read/Write methods without deriving from the class you want to extend. Very flexible and popular design pattern described in the Gang of Four book.

Now I'm not sure if the API you're working with requires a Stream or StreamReader. There is a significant distinction between the two. A StreamReader works at the text level and operations on characters/lines. A Stream works at the binary level and operates on bytes. In other words, the StreamReader is expected to be able to decode the bytes into text so that the consumer doesn't need to be concerned about the encoding. Use a Stream when encoding doesn't matter (such as when compressing or encyrpting) and use a StreamReader when working with text data.

From what it sounds like, a StreamReader would make more sense here. If the API can accept a StreamReader, just derive your own from TextReader and override its ReadLine method so that the first call returns the line of text you need appended and subsequent calls just function as normal.

The other option is to just use a StringWriter/StringReader and stuff it all into an in-memory string buffer, manipulate it, then pass it.




回答2:


The easiest way might be to wrap the stream as an IEnumerable and filter with 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();
    }
}

The sequence above filters only integers, but its easy enough to write a better filter to handle all of the inputs you want.



来源:https://stackoverflow.com/questions/994382/filtering-streams-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!