Начнем с того, что ваш пример недопустим - символ X
в вашем примере находится в позициях (0,3,9,10)
, а не (1,3,7,8)
. Вы исключаете символы перевода строки из своего счета и начинаете счет с индекса 1, когда вы должны начинать с нуля.
Единственный способ связать абсолютные позиции с номерами строк - сопоставить позиции разрывов строк для сравнения. Сделать это на лету, как уже говорили другие, не сложно - просто медленно и утомительно. Если вы собираетесь выполнить несколько поисков, и вы знаете, что данные не изменятся в промежутке времени, вы должны создать статическую карту. Для этого вы можете использовать Список или Карту, но есть класс с именем SizeSequence , который идеально подходит для этой цели. Проверьте это:
import javax.swing.SizeSequence;
public class Test
{
static SizeSequence createLineMap(String s)
{
String[] lines = s.split("(?<=\n)");
SizeSequence sseq = new SizeSequence(lines.length);
for (int i = 0; i < lines.length; i++)
{
sseq.setSize(i, lines[i].length());
}
return sseq;
}
public static void main(String[] args) throws Exception
{
String input = "X2\nX\n4\n56XX";
SizeSequence lineMap = createLineMap(input);
String target = "X";
int pos = -1;
while ((pos = input.indexOf("X", pos+1)) != -1)
{
System.out.printf("'%s' found in line %d (index %d)%n",
target, lineMap.getIndex(pos) + 1, pos);
}
}
}
выход:
'X' found in line 1 (index 0)
'X' found in line 2 (index 3)
'X' found in line 4 (index 9)
'X' found in line 4 (index 10)
Обратите внимание, как я делю на lookbehind (?<=\n)
вместо просто \n
. Таким образом я гарантирую, что количество символов каждой строки включает перевод строки; все символы должны быть подсчитаны. (И на этом примечании я знаю, что есть проблемы с различными разделителями строк и суррогатными парами, но я оставлю их для ясности.)
Вы можете использовать ту же технику для файла, заменив метод findWithinHorizon()
сканера вместо split()
и 'indexOf () `.