Следующий код создает функцию Which_Line_for_Position (pos) , которая дает номер строки для позиции pos , то есть номер строки , в которой находится символ, расположенный в файле в позиции pos .
Эта функция может использоваться с любой позицией в качестве аргумента, независимо от значения файлаТекущее положение указателя и из истории перемещений этого указателя до вызова функции.
Таким образом, с этой функцией не ограничивается определение номера текущей строки только во время непрерывной итерации полинии, как в случае с решением Грега Хьюгилла.
with open(filepath,'rb') as f:
GIVE_NO_FOR_END = {}
end = 0
for i,line in enumerate(f):
end += len(line)
GIVE_NO_FOR_END[end] = i
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = i+1
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
.
Это же решение можно записать с помощью модуля fileinput :
import fileinput
GIVE_NO_FOR_END = {}
end = 0
for line in fileinput.input(filepath,'rb'):
end += len(line)
GIVE_NO_FOR_END[end] = fileinput.filelineno()
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = fileinput.filelineno()+1
fileinput.close()
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
Но у этого решения есть некоторые неудобства:
- необходимо импортировать модуль fileinput
- оно удаляет все контекстНет файла!Должно быть что-то не так в моем коде, но я не знаю fileinput достаточно, чтобы найти это.Или это нормальное поведение функции fileinput.input () ?
- . Кажется, что файл сначала полностью читается, прежде чем можно будет запустить любую итерацию.Если это так, для файла очень большой, размер файла может превышать объем оперативной памяти.Я не уверен в этом: я пытался протестировать файл размером 1,5 ГБ, но он довольно длинный, и на данный момент я упустил этот пункт.Если этот пункт верен, он представляет собой аргумент для использования другого решения с enumerate ()
.
Пример:
text = '''Harold Acton (1904–1994)
Gilbert Adair (born 1944)
Helen Adam (1909–1993)
Arthur Henry Adams (1872–1936)
Robert Adamson (1852–1902)
Fleur Adcock (born 1934)
Joseph Addison (1672–1719)
Mark Akenside (1721–1770)
James Alexander Allan (1889–1956)
Leslie Holdsworthy Allen (1879–1964)
William Allingham (1824/28-1889)
Kingsley Amis (1922–1995)
Ethel Anderson (1883–1958)
Bruce Andrews (born 1948)
Maya Angelou (born 1928)
Rae Armantrout (born 1947)
Simon Armitage (born 1963)
Matthew Arnold (1822–1888)
John Ashbery (born 1927)
Thomas Ashe (1836–1889)
Thea Astley (1925–2004)
Edwin Atherstone (1788–1872)'''
#with open('alao.txt','rb') as f:
f = text.splitlines(True)
# argument True in splitlines() makes the newlines kept
GIVE_NO_FOR_END = {}
end = 0
for i,line in enumerate(f):
end += len(line)
GIVE_NO_FOR_END[end] = i
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = i+1
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
print '\n'.join('line %-3s ending at position %s' % (str(GIVE_NO_FOR_END[end]),str(end))
for end in end_positions)
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
print
for x in (2,450,320,104,105,599,600):
print 'pos=%-6s line %s' % (x,Which_Line_for_Position(x))
результат
line 0 ending at position 25
line 1 ending at position 51
line 2 ending at position 74
line 3 ending at position 105
line 4 ending at position 132
line 5 ending at position 157
line 6 ending at position 184
line 7 ending at position 210
line 8 ending at position 244
line 9 ending at position 281
line 10 ending at position 314
line 11 ending at position 340
line 12 ending at position 367
line 13 ending at position 393
line 14 ending at position 418
line 15 ending at position 445
line 16 ending at position 472
line 17 ending at position 499
line 18 ending at position 524
line 19 ending at position 548
line 20 ending at position 572
line 21 ending at position 600
pos=2 line 0
pos=450 line 16
pos=320 line 11
pos=104 line 3
pos=105 line 4
pos=599 line 21
pos=600 line None
.
Тогда, имея функцию Which_Line_for_Position () , легко получить номер текущей строки: просто пропустив f.tell () в качестве аргумента функции
Но ПРЕДУПРЕЖДЕНИЕ : при использовании f.tell () и перемещении указателя файла вфайл, абсолютно необходимо, чтобы файл был открыт в двоичном режиме: 'rb' или 'rb +' или 'ab' или ....