我有一个要逐行读取的字符串,但我还需要有行定界符,不幸的是,StringReader.ReadLine 会修剪它(与保留它的 ruby 不同)。实现这一目标最快、最稳健的方法是什么?
我一直在考虑的替代方案:
- 逐个字符读取输入并每次检查行分隔符
- 使用正向预测的 RegExp.Split
或者,我只关心行定界符,因为我需要知道字符串中的实际位置,并且定界符可以是一个或多个字符长。因此,如果我能取回光标在字符串中的实际位置也很好,但 StringReader 没有此功能。
编辑:这是我当前的实现。通过返回空字符串指定文件结尾。
StringBuilder line = new StringBuilder();
int r = _input.Read();
while (r >= 0)
{
char c = Convert.ToChar(r);
line.Append(c);
if (c == '\n') break;
if (c == '\r')
{
int peek = _input.Peek();
if (peek == -1) break;
if (Convert.ToChar(peek) != '\n') break;
}
r = _input.Read();
}
return line.ToString();
最佳答案
您是否担心文件之间(即来自 Unix/Mac 与 Windows)或文件内部的不一致?
如果您知道各个文件与自身 一致,一个非常简单的优化方法是只逐个字符地读取第一行并弄清楚分隔符是什么。然后确定任何其他线的确切位置将是简单的数学。
如果做不到这一点,我想我会走逐个字符的路线。正则表达式似乎太“聪明”了。这听起来像是一个复杂的函数,我认为最重要的是让它易于编写、阅读、理解,最重要的是使其易于调试。
还有另一种方法可以做到这一点,如果您的数据源是流,这种方法会更有效。不幸的是,正如您的评论中所提到的那样,您必须先创建一个;但是,无论如何我都会包含解决方案,它可能会给您一些启发:
public IEnumerable<int> GetLineStartIndices(string s)
{
yield return 0;
byte[] chars = Encoding.UTF8.GetBytes(s);
using (MemoryStream stream = new MemoryStream(chars))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
while (reader.ReadLine() != null)
{
yield return stream.Position;
}
}
}
}
这将返回每行的起始位置。显然,您可以调整它以执行您需要的任何其他操作,即用您阅读的实际行执行其他操作。
请注意,这必须复制字符串才能创建字节数组,因此它确实不适合非常大的字符串。不过,它比逐个字符的方法好一点,更不容易出错,所以如果字符串不是兆字节长,也许值得考虑。
关于c# - 在不修剪行定界符的情况下读取c#中的一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2215162/