1

在 c# 中逐行过滤流/阅读器的最简单方法是什么(有点像将 sed 放在管道中间)。我想将 iCalendar 文件提供给 DDay.iCal 但 DDay.iCal 在“VERSION:5.1.1”上死掉,因为它需要一个数字或数字分号数字(其中数字是数字(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”这样无害的东西来代替它。

解析器接口采用阅读器或流。

无论如何,我尝试在这里使用代码并且它可以工作(在过滤的 ReadLine 之上重新实现 TextReader)。

4

2 回答 2

8

System.IO.Stream 使用装饰器模式,因此很容易创建自己的包装底层流。这允许诸如 CryptoStream 和 GZipStream 之类的流包装任何其他 Stream 实例并有效地“覆盖”其读/写方法,而无需从您要扩展的类派生。Gang of Four 书中描述的非常灵活和流行的设计模式。

现在我不确定您使用的 API 是否需要 Stream 或 StreamReader。两者有显着区别。StreamReader 在文本级别工作,对字符/行进行操作。Stream 在二进制级别上工作并且对字节进行操作。换句话说,StreamReader 应该能够将字节解码为文本,这样消费者就不需要关心编码。在编码无关紧要时使用 Stream(例如在压缩或加密时),在处理文本数据时使用 StreamReader。

听起来,StreamReader 在这里会更有意义。如果 API 可以接受 StreamReader,只需从 TextReader 派生您自己的并覆盖其 ReadLine 方法,以便第一次调用返回您需要附加的文本行,随后的调用正常运行。

另一种选择是仅使用 StringWriter/StringReader 并将其全部填充到内存中的字符串缓冲区中,对其进行操作,然后传递它。

于 2009-06-15T03:33:39.447 回答
5

最简单的方法可能是将流包装为 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();
    }
}

上面的序列只过滤整数,但它很容易编写一个更好的过滤器来处理你想要的所有输入。

于 2009-06-15T03:21:28.477 回答