#python #python-3.x
#python #python-3.x
Вопрос:
Я пытаюсь написать скрипт на Python, который разбивает непрерывную строку на строки, когда max_line_length
было превышено.
Он не должен прерывать слова и, следовательно, выполняет поиск по последнему вхождению символа пробела, который будет заменен символом новой строки.
По какой-то причине он не прерывается в пределах указанного предела.
Например, при определении max_line_length = 80
текст иногда прерывается на 82 или 83 и т.д.
С некоторых пор я пытаюсь решить проблему, однако мне кажется, что у меня туннельное видение и я не вижу проблемы здесь:
#!/usr/bin/python
import sys
if len(sys.argv) < 3:
print('usage: $ python3 breaktext.py <max_line_length> <file>')
print('example: $ python3 breaktext.py 80 infile.txt')
exit()
filename = str(sys.argv[2])
with open(filename, 'r') as file:
text_str = file.read().replace('n', '')
m = int(sys.argv[1]) # max_line_length
text_list = list(text_str) # convert string to list
l = 0; # line_number
i = m 1 # line_character_index
index = m 1 # total_list_index
while index < len(text_list):
while text_list[l * m i] != ' ':
i -= 1
pass
text_list[l * m i] = 'n'
l = 1
i = m 1
index = m 1
pass
text_str = ''.join(text_list)
print(text_str)
Комментарии:
1. Почему вы поместили имена переменных в комментарии? Зачем преобразовывать строку в список, когда вы можете просто разрезать или проиндексировать строку? Почему вы предполагаете, что все строки имеют одинаковую длину в
l * m
? Я думаю, что последнее является частью вашей проблемы, потому что невозможно сказать, как далекоi
продвинулись назад, прежде чем пропустить вперед другиеm
символы… вполне возможно, что более ранняя строка снова была разделена.2. @YannVernier 1) Потому что литералы делают код более читаемым, чем слишком длинные объяснительные имена переменных. 2) Я привык работать с указателями из
C
, в Python невозможно изменить строку посредством индексации, однако со списками это возможно. 3) Что вы имеете в виду, предполагая, что все строки имеют одинаковую длину? Есть только одна очень длинная строка, которая должна быть отформатирована в несколько маленьких строк.3.
textwrap
Модуль stdlib, вероятно, будет делать то, что вы хотите, с гораздо меньшим количеством кода с вашей стороны.4. @PaulMcG
import textwrap
withprint(textwrap.fill(text_str, width=m))
справился с задачей, тай! Тем не менее, я не понимаю, в чем проблема выше :/
Ответ №1:
Я думаю, мы возьмем это сверху.
text_str = file.read().replace('n', '')
Вот одно предположение о входных данных, я не знаю, верно ли это. Вы заменяете все символы новой строки ничем; если рядом с ними не было пробелов, это означает, что приведенный ниже код никогда не будет прерывать строки в одних и тех же местах.
text_list = list(text_str) # convert string to list
Это разбивает входной файл на строки из одного символа. Я думаю, вы могли бы сделать это, чтобы сделать его изменяемым, чтобы вы могли заменять отдельные символы, но это очень дорогостоящая операция и теряет все функции строки. Python — это язык высокого уровня, который позволит вам вместо этого разбиваться, например, на слова.
index = m 1 # total_list_index
while index < len(text_list):
#...
index = m 1
Давайте рассмотрим, что это значит. Мы не входим в цикл, если index
превышает text_list
длину. Но index
продвигается с шагом m 1
. Итак, мы разделяем math.floor(len(text)/(max_line_length 1))
время. Если каждая строка не содержит ровно max_line_length
символов, не считая пробела, который мы заменяем новой строкой, это слишком мало раз. Слишком мало раз означает слишком длинные строки, по крайней мере, в конце.
l = 0; # line_number
i = m 1 # line_character_index
#loop:
while text_list[l * m i] != ' ':
i -= 1
text_list[l * m i] = 'n'
l = 1
i = m 1
Это усложняет математику индекса. Совершенно очевидно, что один индекс, который мы когда-либо использовали, l * m i
. Это происходит довольно странным образом; он ищет пробел в обратном направлении, затем переходит вперед с l
увеличением и i
сбросом. В какую бы позицию он ни вернулся, она теряется, поскольку все переходы выполняются с шагом m
.
Давайте применим m=5
к строке "Fee fie faw fum who did you see now"
. Для первой итерации 0 * 5 5 1
попадает на второе слово и i
возвращается к первому пробелу. Тогда первая строка — «Плата», как и ожидалось. Второй поиск начинается с 1*5 5 1
, который является пробелом, а вторая строка становится «fie faw», что уже превышает наш лимит в 5! Причина в том, что l * m
это не начало строки; на самом деле это в середине «fie», несоответствие, которое может только увеличиваться по мере продолжения работы с файлом. Он увеличивается всякий раз, когда вы отделяете строку, которая короче m
.
Решение включает в себя запоминание того, где вы сделали разделение. Это может быть так же просто, как заменить l * m
на index
и обновить его на index = i
вместо m 1
.
Еще один странный эффект возникает, если вы когда-либо сталкиваетесь со словом, превышающим максимальную длину строки. Помимо значения, что строка длиннее предела, i
все равно будет выполняться поиск в обратном направлении, пока не найдет пробел; тогда этот пробел может быть вообще в более ранней строке, создавая как слишком короткие строки, так и слишком длинные. Это результат обработки всего текста как одного массива и без ограничения того, какой раздел мы рассматриваем.
Лично я бы предпочел использовать встроенные методы Python, такие как str.rindex
, которые могут найти определенный символ в заданной области внутри строки:
s = "Fee fie faw fum who did you see now"
maxlen = 5
start = 8
end = s.rindex(' ', start, start maxlen)
print(s[start:end])
start = end 1
Мы также, как указал PaulMcG, можем использовать полные «батарейки в комплекте» и использовать стандартный библиотечный модуль textwrap для всей задачи.