在c#中逐行过滤流/阅读器的最简单方法是什么(有点像将sed放在管道中间)。我想将iCalendar文件提供给DDay.iCal,但DDay.iCal在“VERSION:5.1.1”上死亡,因为它需要一个数字或数字SEMICOLON编号(其中数字是数字(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”之类的无害替换它。
解析器接口需要读取器或流。
无论如何,我尝试使用代码here并且它可以工作(在过滤的ReadLine之上重新实现TextReader)。
答案 0 :(得分:7)
System.IO.Stream使用装饰器模式,因此可以很容易地创建自己的包装底层流。这允许诸如CryptoStream和GZipStream之类的流包装任何其他Stream实例并有效地“覆盖”其读/写方法,而不从您想要扩展的类派生。 “四人帮”一书中描述的非常灵活和流行的设计模式。
现在我不确定您使用的API是否需要Stream或StreamReader。两者之间存在显着差异。 StreamReader在 text 级别工作,对字符/行进行操作。 Stream工作在二进制级别并按字节操作。换句话说,期望StreamReader能够将字节解码为文本,以便消费者不需要关心编码。在编码无关紧要时(例如压缩或加密时)使用Stream,并在处理文本数据时使用StreamReader。
听起来,StreamReader在这里会更有意义。如果API可以接受StreamReader,只需从TextReader派生自己的并重写其ReadLine方法,以便第一个调用返回您需要附加的文本行,后续调用只是正常运行。
另一种选择是使用StringWriter / StringReader并将其全部填充到内存中的字符串缓冲区中,对其进行操作,然后传递它。
答案 1 :(得分: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();
}
}
上面的序列只过滤整数,但它很容易编写一个更好的过滤器来处理你想要的所有输入。