Функция обработки текста в Python с переносом слов - PullRequest
1 голос
/ 04 апреля 2019

Я создаю текстовый процессор и пытаюсь реализовать функцию переноса слов.

Учитывая максимальное количество символов в строке, за которым следует список слов, я хочу вернуть коллекцию строк, где каждая строка содержит как можно больше слов, соединенных пробелом. Длина каждой строки не должна превышать максимальную длину.

  • Должно быть ровно один пробел между каждым словом в каждой строке вывода.
  • Каждое слово будет состоять из строчных букв английского алфавита.
  • Знаков препинания не будет.
  • Максимальная длина каждого слова может считаться постоянной.
  • Ни одно отдельное слово не будет длиннее указанной максимальной длины символов в строке.
import sys

# Prints to standard output.
def wrapLines(line_length, words):
  curr_line = ""
  for word in words:
    if len(curr_line) + len(word) >= line_length:
      curr_line = ""
    else:
      curr_line += word
      print curr_line


def main():
  first_line = None
  words = []

  first_arg = True
  for line in sys.stdin:
    if len(line.strip()) == 0:
      continue

    line = line.rstrip()

    if first_arg:
      lineLength = line
      first_arg = False
    else:
      words.append(line)

  wrapLines(lineLength, words)

main()

Ввод:

13
abc
xyz
foobar
cuckoo
seven
hello

Мой вывод продолжает печатать все слова, прикрепленные друг к другу, вместо переноса строки.

abc
abcxyz
abcxyzfoobar
abcxyzfoobarcuckoo
abcxyzfoobarcuckooseven
abcxyzfoobarcuckoosevenhello

Ожидаемый результат:

abc xyz
foobar cuckoo
seven hello

Ответы [ 2 ]

2 голосов
/ 04 апреля 2019

Там есть пара проблем - наиболее важным является то, что вы читаете первую строку в stdin и используете ее как lineLength, но вы не конвертируете ее в число . Таким образом, ваше значение в переменной lineLengthline_length внутри функции-оболочки) является строкой - и сравнение

 if len(curr_line) + len(word) >= line_length:

Всегда сравнивает длину предложенной строки вывода с левой стороны со строкой - если вы используете последнюю версию Python, эта строка будет ошибочной, так как совмещение чисел и строк теперь (справедливо) запрещено. В Python 3, однако, это выражение всегда True - нумераторы всегда рассматриваются как <, чем строки - поэтому код для строки, превышающей ограничение, никогда не запускается.

Вторая ошибка заключается просто в том, что вы не объединяете пробелы в строку строки, а просто объединяете слова с помощью +=, но не добавляете пробелы.

Третья ошибка заключается в том, что вы всегда печатаете строку, вычисляемую внутри цикла, независимо от того, превышена длина строки или нет.

И последнее, но не менее важное - как я уже говорил в комментариях выше: больше не используйте Python 2 - есть причина, по которой они создали Python 3, и это потому, что язык эволюционировал.

И, не так неправильно, но рекомендуется: ваша функция должна просто обрабатывать текст и возвращать данные - если вы хотите напечатать результаты, вы можете распечатать их из функции вызывающего. Таким образом, функция остается достаточно универсальной и может использоваться в других контекстах.

Кроме того, рекомендуемый размер отступа для приложений Python - 4. Хотя использование 2 пробелов является допустимым кодом, он практически нигде не используется (но в частном коде некоторых известных компаний - но это их бизнес).

Ваш фиксированный код плюс рекомендации - будут работать как в Python 2, так и в 3:

import sys

def wrapLines(line_length, words):
    curr_line = ""
    result = []
    for word in words:
        if len(curr_line) + len(word) + 1 >= line_length:
            result.append(curr_line)
            curr_line = ""
        else:
            curr_line += " " + word
    if curr_line:
        result.append(currline)
    return result


def main():
    first_line = None
    words = []

    first_arg = True
    for line in sys.stdin:
        if len(line.strip()) == 0:
            continue

        line = line.rstrip()

        if first_arg:
            line_length = int(line)
            first_arg = False
        else:
            words.append(line)

    print("\n".join(wrapLines(line_length, words)))


main()
0 голосов
/ 04 апреля 2019

Во-первых, насколько я могу судить, вы не указали желаемый lineLength, поэтому я приму 14 исходя из ожидаемого результата. Лично я думаю, что все это можно упростить в одну функцию, которая перебирает ваш список входных слов, и если он может добавить его, не превышая длину строки, он добавит к строке, в противном случае он добавит строку в наш список вывода (видя так как он не может обработать следующее слово), а затем сбросить строку. Я реализовал цикл while, поэтому на итерации, которая требует сброса, он может просто не увеличивать счетчик (i в моем случае), а затем он будет индексировать это же место на следующей итерации, и он будет первым в строке быть добавленным в только что сброшенную строку. Я сделал это в Python 3.X, поэтому он может не работать в 2.X, но в этом случае это будет '{}'.format, и вы можете вместо этого использовать оператор %. В конце цикла есть еще один wrapped_words.append(current_line.strip()), чтобы мы могли взять и последнюю строку.

Мое решение:

words_input = ['13', 'abc', 'xyz', 'foobar', 'cuckoo', 'seven', 'hello']

def wrap_words(words_to_wrap, max_line_length):
    wrapped_words = []
    current_line = ''
    i = 0
    while i < len(words_to_wrap):
        if len(current_line) + len(words_to_wrap[i]) + 1 > max_line_length:  # +1 for the space
            wrapped_words.append(current_line.strip())
            current_line = ''
        else:
            current_line += '{} '.format(words_to_wrap[i])
            i += 1
    if len(current_line):
        wrapped_words.append(current_line.strip())
    return wrapped_words

print(wrap_words(words_input, 14))

Выходы:

['13 abc xyz', 'foobar cuckoo', 'seven hello']

...