从String中的char位置获取行号的最简单方法是什么?

从C#中的字符串中的char位置获取行号的最简单方法是什么? (或获取行的位置(第一个字符串))是否有内置函数? 如果没有这样的function,那么编写扩展名的好方法就像:

public static class StringExt { public static int LineFromPos(this String S, int Pos) { int Res = 1; for (int i = 0; i <= Pos - 1; i++) if (S[i] == '\n') Res++; return Res; } public static int PosFromLine(this String S, int Pos) { .... } } 

编辑:添加方法PosFromLine

Jan的建议稍有不同,没有创建新的字符串:

 var lineNumber = input.Take(pos).Count(c => c == '\n') + 1; 

使用Take限制输入的大小而不必复制字符串数据。

顺便提一下,如果给定的字符换行符,你应该考虑你想要的结果……以及你是否想要将"foo\rbar\rbaz"作为三行处理。

编辑:要回答问题的新的第二部分,你可以做类似的事情:

 var pos = input.Select((value, index) => new { value, index }) .Where(pair => pair.value == '\n') .Select(pair => pair.index + 1) .Take(line - 1) .DefaultIfEmpty(1) // Handle line = 1 .Last(); 

认为这样可行……但我不确定我是否会写出非LINQ方法……

计算子网格输入字符串中的换行符数。

 var lineNumber = input.Substring(0, pos).Count(c=>c == '\n') + 1; 

编辑 :并执行+1因为行号从1开始:-)

如果要在同一个长字符串上多次调用该函数,则此类可能很有用。 它缓存新的行位置,以便稍后它可以为GetLineGetLine O(1)执行O(log(字符串中的换行符))查找。

 public class LineBreakCounter { List lineBreaks_ = new List(); int length_; public LineBreakCounter(string text) { if (text == null) throw new ArgumentNullException(nameof(text)); length_ = text.Length; for (int i = 0; i < text.Length; i++) { if (text[i] == '\n') lineBreaks_.Add(i); else if (text[i] == '\r' && i < text.Length - 1 && text[i + 1] == '\n') lineBreaks_.Add(++i); } } public int GetLine(int offset) { if (offset < 0 || offset > length_) throw new ArgumentOutOfRangeException(nameof(offset)); var result = lineBreaks_.BinarySearch(offset); if (result < 0) return ~result; else return result; } public int Lines => lineBreaks_.Count + 1; public int GetOffset(int line) { if (line < 0 || line >= Lines) throw new ArgumentOutOfRangeException(nameof(line)); if (line == 0) return 0; return lineBreaks_[line - 1] + 1; } } 

这是我的测试用例:

 [TestMethod] public void LineBreakCounter_ShouldFindLineBreaks() { var text = "Hello\nWorld!\r\n"; var counter = new LineBreakCounter(text); Assert.AreEqual(0, counter.GetLine(0)); Assert.AreEqual(0, counter.GetLine(3)); Assert.AreEqual(0, counter.GetLine(5)); Assert.AreEqual(1, counter.GetLine(6)); Assert.AreEqual(1, counter.GetLine(8)); Assert.AreEqual(1, counter.GetLine(12)); Assert.AreEqual(1, counter.GetLine(13)); Assert.AreEqual(2, counter.GetLine(14)); Assert.AreEqual(3, counter.Lines); Assert.AreEqual(0, counter.GetOffset(0)); Assert.AreEqual(6, counter.GetOffset(1)); Assert.AreEqual(14, counter.GetOffset(2)); }