从C#中的字符串中的char位置获取行号的最简单方法是什么? (或获取行的位置(第一个字符串)) 有没有内置功能?如果没有这样的功能,那么编写扩展名的好方法就像:
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
答案 0 :(得分:15)
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方法......
答案 1 :(得分:10)
计算子网格输入字符串中的换行符数。
var lineNumber = input.Substring(0, pos).Count(c=>c == '\n') + 1;
编辑:并执行+1
,因为行号从1开始: - )
答案 2 :(得分:2)
如果要在同一个长字符串上多次调用该函数,则此类可能很有用。它缓存新的行位置,以便稍后它可以执行GetLine
的O(log(换行符))查找GetOffset
的O(1)。
public class LineBreakCounter
{
List<int> lineBreaks_ = new List<int>();
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));
}
答案 3 :(得分:0)
对于那些对javascript或更迭代的方法感兴趣的人。
const {min} = Math
function lineAndColumnNumbersAt(str, pos) {
let line = 1, col = 1
const _pos = min(str.length, pos)
for (let i = 0; i < _pos; i++)
if (str[i] === '\n') {
line++
col = 1
} else
col++
return {line, col}
}
lineAndColumnNumbersAt('test\ntest\ntest', 8)