Возможно ли с помощью Gedit или командной строки изменить каждую четвертую строку текстового файла?

11

Я пытаюсь преобразовать текстовый файл в таблицу, разделенную табуляцией. Мой текстовый файл выглядит примерно так:

Dog
Cat
Fish
Lizard
Wolf
Lion
Shark
Gecko
Coyote
Puma
Eel
Iguana

Стандартные функции поиска и замены в Gedit или LibreOffice позволяют легко заменить конец строки вкладкой. Но если я просто поменяю возврат каретки на вкладки, я получу это:

Dog   Cat   Fish   Lizard   Wolf   Lion   Shark   Gecko   Coyote   Puma   Eel   Iguana

Но мне нужно сделать так, чтобы это выглядело так:

Dog   Cat   Fish   Lizard
Wolf   Lion   Shark   Gecko  
Coyote   Puma   Eel   Iguana

Итак, можно ли поменять местами все символы конца строки для табуляции, кроме каждой четвертой строки?

Я не знаю, можно ли выполнить такую ​​условную итерацию с помощью регулярных выражений внутри такой программы, как Gedit или LibreOffice, поэтому, возможно, это должна быть какая-то функция командной строки? Я даже не знаю, с чего лучше начать.


Обновить:

Я попробовал следующие команды:

sed 'N;N;N;s/\n/\t/g' file > file.tsv

paste - - - - < file > file.tsv

pr -aT -s$'\t' -4 file > file.tsv

xargs -d '\n' -n4 < inputfile.txt

Но когда я пытаюсь открыть полученный tsvфайл в LibreOffice, столбцы не совсем правильные. Я не уверен, означает ли это, что я не выполняю вышеуказанные команды правильно, или я делаю что-то неправильно в функции импорта LibreOffice:

Открытие TSV в Calc

Просто для справки, желаемый результат должен выглядеть так:

Правильные колонки

интервьюер
источник

Ответы:

16

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

sed 'N;N;N;s/\n/\t/g' file > file.tsv

или, что еще проще, добавив символы продолжения строки с обратной косой чертой в каждую строку, к которой вы хотите присоединиться, используя n skip mадресный оператор GNU sed , и добавьте классическую однострочную строку для объединения непрерывных строк:

sed '0~4! s/$/\t\\/' file | sed -e :a -e '/\\$/N; s/\\\n//; ta'

Смотри, например, Sed One-Liners Explained :

  1. Добавьте строку к следующей, если она заканчивается обратной косой чертой "\".

    sed -e :a -e '/\\$/N; s/\\\n//; ta'
    

Однако ИМХО было бы проще с одной из других стандартных утилит обработки текста, например

paste - - - - < file > file.tsv

(количество -будет соответствовать количеству столбцов) или

pr -aT -s$'\t' -4 file > file.tsv

(вы можете опустить, -s$'\tесли вы не против, чтобы вывод был разделен несколькими вкладками).


Странное поведение при повторном импорте, которое вы наблюдаете, почти наверняка связано с тем, что исходный файл имеет окончания строки CRLF в стиле Windows. Если вам нужно работать с файлами из Windows, вы можете выполнить преобразование в команду различными способами, например:

tr -d '\r' < file.csv | paste - - - -

или

sed 'N;N;N;s/\r\n/\t/g' file.csv

Первый удалит ВСЕ возвраты каретки, тогда как последний сохранит CR в конце каждой новой строки (что может быть тем, что вы хотите, если предполагаемый конечный пользователь работает в Windows).

steeldriver
источник
1
Примечание о конце строки в стиле Windows: стандартными инструментами для преобразования между ними и стиля Unix являются dos2unixи unix2dos.
Дэвид Фёрстер
13

Вы можете использовать, xargsчтобы всегда группировать четыре строки в одну, разделенную одним пробелом:

xargs -d '\n' -n4 < inputfile.txt

-d '\n'устанавливает в качестве разделителя ввода символ новой строки, в противном случае он также будет разбит на пробелы. Если у вас есть только одно слово на строку ввода, вы можете даже опустить это.
-n4устанавливает номер аргумента (количество входных элементов в выходной строке) равным 4.

Выход:

Dog Cat Fish Lizard
Wolf Lion Shark Gecko
Coyote Puma Eel Iguana

Или, если вы хотите использовать табуляцию как разделитель вместо пробела, вы можете заменить их позже. Однако, если у вас есть пробелы во входных строках, они также будут заменены:

xargs -d '\n' -n4 | tr ' ' '\t'

Вывод (смотрите в зависимости от ширины вкладки браузера / терминала):

Dog Cat Fish    Lizard
Wolf    Lion    Shark   Gecko
Coyote  Puma    Eel Iguana
Byte Commander
источник
Преимущество этого метода в том, что он ведет себя разумно, даже если общее количество строк ввода не кратно четырем.
Элия ​​Каган
3

Вы также можете использовать:

awk -v ORS="" '{print $1; print NR%4==0?"\n":"\t"}' file > file.tsv 

Две встроенные переменные awk:

  • ORS: O utput R ecord S eparator ( по умолчанию = новая строка). Он добавляется в конце каждой команды печати.
  • NR: N умбра текущего R вл AWK обрабатывает.

Эта команда для каждой строки отображает содержимое первого (и только здесь) столбца. Затем он решает добавить новую строку или вкладку, протестировав остаток от деления NRна 4.

arauk
источник
3

Еще один кратчайший awkподход:

awk '{printf $0 (NR%4?"\t":"\n")}' infile

Это Printf только один столбец с последующим рядом и рядом и ... и ушко \tхарактер после того, как каждый , но будет PRINTF в \newline характер , когда N хариус из R ecord был фактор 4 (где NR%4будет возвращать 0 (ложь) , которая является то , что оператор троичного condition(s)?when-true:when-falseделается.)

αғsнιη
источник
3

Мое решение этого было бы использовать комбинацию sedи sed. Во-первых, вы можете пометить каждую четвертую строку каким-нибудь специальным символом, например >, используя это решение:

В этом случае вы хотите начать со строки 5 и отмечать каждую четвертую строку после нее. В GNU sedэто может быть дано как адрес 5~4. Вы можете использовать эту команду:

sed '5~4s/^/>/' file1 > file2

Затем вам нужно удалить символы новой строки, что можно сделать с помощью sedцикла:

sed ':a;N;s/\n/ /;ba' file2 > file3

Существуют более простые способы преобразования строк в какой-либо другой символ, например с помощью tr:

tr '\n' ' ' < file2 > file3

В любом случае, объединение двух дает

Dog   Cat   Fish   Lizard   >Wolf   Lion   Shark   Gecko   >Coyote   Puma   Eel   Iguana

( sedверсия оставляет завершающий символ новой строки, а trверсия - нет)

После этого вам нужно только конвертировать вставленные вами специальные символы в новые строки; см., например, Преобразование файла с разделителями табуляции для использования новых строк . В этом случае перейдите >на новую строку:

sed 'y/>/\n/' file3 > outfile

Команда yвыполняет ту же функцию, что trи преобразование одного символа в другой, но здесь вы можете использовать sкоманду одинаково хорошо. При помощи sвам нужно gоперировать каждым совпадением в строке ( sed 's/>/\n/g').

Вместо создания двух промежуточных файлов вы можете использовать каналы:

$ sed '5~4s/^/>/' file | sed ':a;N;s/\n/ /;ba' | sed 'y/>/\n/'
Dog Cat Fish Lizard 
Wolf Lion Shark Gecko 
Coyote Puma Eel Iguana

Если конечные пробелы являются проблемой, вы можете добавить еще одну команду для их удаления:

| sed 's/ $//'
spaceman117X
источник
2

Ради «полноты» вот чистое решение bash:

#!/usr/bin/env bash

sep=$'\t'

while read one \
      && read two \
      && read three \
      && read four
do
  printf "%s\n" "$one$sep$two$sep$three$sep$four"
done

Работает также с пробелами, при условии, что IFSправильно установлен (что должно по умолчанию, AFAIK). Более того, я думаю , что это может быть даже сценарий переносимой оболочки, работающий с любой POSIX-совместимой оболочкой.

Даниэль Жур
источник
1
Это вообще не переносимо для POSIX-совместимых оболочек, потому что $' 'POSIX не требует формы цитирования. Например, в dash(который обеспечивает shпо умолчанию в Ubuntu) работает printf '%s\n' $'a\tb'только вывод $a\tb. Это не значит, что это бесполезно; это работает в Bash. Однако, как и в случае с некоторыми другими решениями, опубликованными людьми, он выдает неполный вывод, если число строк ввода не кратно четырем. Кроме того, я рекомендую использовать read -r, так как нет никаких оснований думать, что расширение выходных данных обратной косой черты во входном файле желательно здесь.
Элия ​​Каган
Вы могли бы просто сделатьprintf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
Terdon
2

Макрос vim (записанный с помощью q) может применить вашу операцию, затем пропустить три строки. Затем вы просто запускаете этот макрос n раз.

например:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q
rackandboneman
источник
2

Так как вы попросили решение Gedit, что-то вроде этого должно работать:

Найти:

(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+

Заменить:

\1\t\2\t\3\t\4\n

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

Как это устроено:

Первый шаг - найти последовательность символов слова с \ w + и записать результаты в переменную \ 1, заключив скобки в выражение:

(\w+)

Затем мы ищем серию символов конца строки, \ r и \ n, или CR и LF. Так как файлы в формате Windows используют оба, мы создаем класс символов, заключая эти два символа в квадратные скобки. Плюс заставляет его искать один или несколько символов:

[\r\n]+

Наконец, мы повторяем это еще 3 раза, сохраняя каждое последующее слово в переменных \ 2, \ 3 и \ 4. Это делает нашу замену выражением простым. Нам просто нужно поместить символы табуляции \ t и символ новой строки \ n в соответствующие места для форматирования, которое вам нужно.

Джейсон Вуд
источник