5

Многие текстовые файлы в Интернете разбиты на слова до того, как строка достигает 80-го символа. Я понимаю, что это желательно для тех, кто использует 80-символьные терминалы. Тем не менее, я люблю посылать более длинные статьи моему Kindle, но эти файлы выглядят очень плохо на нем. Смотрите эту картинку:Это старая проблема LWN, которая автоматически загружается и собирается в .mobi

Разделение на 80 символов ясно видно, когда текст заканчивается в середине строки.

У меня вопрос: как развернуть / вырезать эти строки? Метод "от руки", конечно, не обсуждается. РЕДАКТИРОВАТЬ: Позвольте уточнить: я прошу сценарий или другой метод, который можно было бы запустить из терминала Linux. bash / ruby / python / perl / awk в порядке.

Кроме того, предположим, что у меня есть только открытый текст, LWN - просто пример.

5 ответов5

5

Ответ с использованием fmt кажется, заключается в том, чтобы обернуть текст, а не развернуть его.

В общем, это может быть сложной проблемой. Например, для различения смежных строк текста, которые намеренно завершены рано (например, маркеры), и смежных строк свободного текста может потребоваться некоторый контекст. Различать слова, разделенные на строки и слова, также трудно.

Обычной формой для прозы, однако, являются смежные обернутые строки текста, образующие абзац, разделенный одной пустой новой строкой.

Это можно развернуть, используя следующий, довольно сложный, sed один вкладыш:

sed -n '/.+/ H; /^$/ { x; s/\n/ /g; s/$/\n/ ; p}'

В качестве альтернативы вы можете предпочесть крошечный скрипт на python, особенно если вы собираетесь обрабатывать некоторые особые случаи:

import sys
paragraph = []

for line in sys.stdin:
    line = line.strip()
    if line:
        paragraph.append(line)
    else:
        print ' '.join(paragraph).replace('  ', ' ')
        paragraph = []
if paragraph:
    print ' '.join(paragraph).replace(' ', ' ')

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

1

Я только что наткнулся на этот пост, когда искал способ сделать это с помощью sed. Вот мой сценарий оболочки, который я использовал для большей части моей распаковки:

# unwrap text with linebreaks in paragraphs and blank lines between paragraphs
# This script reads stdin and writes stdout
# cat is used to read stdin into a here-string so that lnum may be printed at the end, outside of the loop

oline=""
lnum=0

while read aline
do
    lnum=$((++lnum))
    # check for probable blank line by its length, end of paragraph
    if [ ${#aline} -lt 3 ]
        then
        # output concatenated line
        echo "$oline"
        # output blank line
        echo ""
        # prepare for the next paragraph
        oline=""
    else
        # otherwise add it to the unwrapped line
        oline=$(echo $oline|tr -d '\n'|tr -d '\r')
        oline="$oline $aline"
    fi
done <<< "$(cat)"

echo "$lnum"
exit 0
1

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

Как развернуть эти строки?

Используйте инструмент командной строки unix 'fmt', как это было предложено Раулем Салинасом-Монтеагудо. Измените длину строки (-w ##) на полезное число. Вы можете попробовать 65 или 55, или 1111 или больше.

Пример:

Этот файл из метеорологического бюро (https://forecast.weather.gov/product.php?site=NWS&issuedby=AT&product=TWO&format=txt&version=1&glossary=0) содержит жесткую строку, встроенную в текст абзаца. Я хочу, чтобы переводы были только в конце абзаца. Передача вывода в 'fmt -w 1111' (для абзацев длиной менее 1111 символов) решает проблему:

/usr/local/bin/w3m -dump 'https://forecast.weather.gov/product.php?site=NWS&issuedby=AT&product=TWO&format=txt&version=1&glossary=0' | sed -n '/TWOAT/,/Forecaster/p' | fmt -w 1111

,

Изменяет внешний вид от этого:

The National Hurricane Center is issuing advisories on
Tropical Storm Beryl, located a couple of hundred miles
east of the Lesser Antilles, and on Tropical Storm
Chris, located more than one hundred miles south of the
North Carolina Outer Banks.

Tropical cyclone formation is not expected during the
next 5 days.

к этому:

The National Hurricane Center is issuing advisories on Tropical Storm Beryl, located a couple of hundred miles east of the Lesser Antilles, and on Tropical Storm Chris, located more than one hundred miles south of the North Carolina Outer Banks.

Tropical cyclone formation is not expected during the next 5 days.
1

Особые случаи, как сказал Атт Риг ...

Я нашел этот вопрос, потому что хотел "развернуть" выходные данные из программы fortune , которая, к сожалению, даже не стандартизирована - некоторые файлы cookie состояния заключаются в 78 символов, другие в 77, 76 или даже 75.
Мой сценарий пытается определить, была ли новая строка вставлена специально или из-за ограничения длины, путем определения того, будет ли строка нарушать ограничение длины, если она не была разорвана на этой точной длине (то есть, будет ли она слишком длинной, если она также включены первые слова из следующей строки). В качестве полезного побочного эффекта, если следующая строка начинается с пробела, первое слово (разделенное пробелом) является пустой строкой, поэтому абзацы с отступом никогда не объединяются в строку над ними.

#!/usr/bin/python3

import sys
import fileinput

lines = list(fileinput.input())
lines = [l.strip('\r\n') for l in lines]

for i, l in enumerate(lines):
    # We need to account for 8-char-wide tabulators when calculating our line
    # length, but still want to print the original \t characters verbatim
    sanitized_line = l.replace('\t', ' '*8)

    # Is there a next line?
    if i+1 < len(lines):
        sanitized_next_line = lines[i+1].replace('\t', ' '*8)
    else:
        sanitized_next_line = ''

    next_line_first_word = sanitized_next_line.split(' ', 1)[0]

    if next_line_first_word != '':
        extended_line = sanitized_line + ' ' + next_line_first_word
    else:
        extended_line = sanitized_line

    if len(sanitized_line) <= 78 and len(extended_line) > 74:
        # This line was wrapped due to 78-char limit => unwrap it!
        sys.stdout.write(l + ' ')
    else:
        sys.stdout.write(l + '\n')
-2

Я думаю, что именно то, что вы хотите, выполняется простым:

fmt -w 80 < input > output

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .