sed: Игнорировать начальные пробелы при глобальной замене

sed: Игнорировать начальные пробелы при глобальной замене

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

     This is     an indented      paragraph. The   indentation   should not be changed.
This is the     second   line  of the    paragraph. 

Станет:

     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

Я пробовал разные варианты

/^[ \t]*/!s/[ \t]+/ /g

Любые идеи были бы хорошы.

решение1

$ sed 's/\>[[:blank:]]\{1,\}/ /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

Выражение, которое я использовал, соответствует одному или нескольким [[:blank:]](пробелам или табуляциям)после слова, и заменяет их одним пробелом. \>Соответствует границе нулевой ширины между символом слова и не-символом слова.

Это было протестировано с родным OpenBSD sed, но я думаю, что это должно работать sedи с GNU. GNU sedтакже использует \bдля сопоставления границ слов.

Вы также можете использовать sed -Eсокращение до

sed -E 's/\>[[:blank:]]+/ /g' file

Опять же, если \>у вас не работает GNU sed, используйте \bвместо этого.


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

     This is     an indented      paragraph.        The   indentation   should not be changed.
This is the     second   line  of the    paragraph.

Для этого подойдет немного более сложный вариант:

$ sed -E 's/([^[:blank:]])[[:blank:]]+/\1 /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

При этом любой непустой символ, за которым следует один или несколько пробелов, заменяется на непустой символ и один пробел.

Или, используя стандарт sed(и очень маленькую оптимизацию, которая будет выполнять замену только в том случае, если естьдва или болеепробелы/табуляции после не-пробела/табуляции),

$ sed 's/\([^[:blank:]]\)[[:blank:]]\{2,\}/\1 /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

решение2

POSIXly:

sed 's/\([^[:space:]]\)[[:space:]]\{1,\}/\1 /g; s/[[:space:]]*$//'

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

Связанный контент