Как объединить текст буквенных строк с числовыми строками в оболочке?

10

У меня есть файл с таким текстом:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

и т.д...

И я хочу сопоставить буквенные линии с числовыми линиями, чтобы они выглядели так:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Кто-нибудь знает простой способ добиться этого?

NWS
источник
Вы упоминаете emacs... Вы ищете elispрешение или как запустить shell-скрипт из Emacs?
Peter.O

Ответы:

3

Один из способов использования perl:

Содержание script.pl:

use warnings;
use strict;

## Check arguments.
die qq[Usage: perl $0 <input-file>\n] unless @ARGV == 1;

my (@alpha, @digit);

while ( <> ) {
        ## Omit blank lines.
        next if m/\A\s*\Z/;

        ## Remove leading and trailing spaces.
        s/\A\s*//;
        s/\s*\Z//;

        ## Save alphanumeric fields and fields with
        ## only digits to different arrays.
        if ( m/\A[[:alpha:]]+\Z/ ) {
                push @alpha, $_;
        }
        elsif ( m/\A[[:digit:]]+\Z/ ) {
                push @digit, $_;
        }
}

## Get same positions from both arrays and print them
## in the same line.
for my $i ( 0 .. $#alpha ) {
        printf qq[%s %s\n], $alpha[ $i ], $digit[ $i ];
}

Содержание infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Запустите это как:

perl script.pl infile

И результат:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890
Birei
источник
Интересные ... Два ваших регулярных выражений линии замещения , которые удалить начальные и конечные пробелы бегают в 1,6 раза быстрее , чем в одной строке , которая использует ссылочность и не жадный: s/\A\s*(.*?)\s*\Z/\1/.
Peter.O
4

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

awk -v RS="" '{for(i=1; i<=NF; i++) a[i]=$i
  getline
  for(i=1; i<=NF; i++) print a[i] " " $i
  print ""}' file
jfg956
источник
4
<input sed -nr '/^[A-Z]{4}$/,/^$/w out1
                /^[0-9]{4}$/,/^$/w out2'
paste -d' ' out1 out2 |sed 's/^ $//' 

или, за один шаг, без временных файлов

paste -d' ' <(sed -nr '/^[A-Z]{4}$/,/^$/p' input) \
            <(sed -nr '/^[0-9]{4}$/,/^$/p' input) | sed 's/^ $//' 

Последний sedшаг удаляет разделитель на пустых строках, который вводится paste...

Peter.O
источник
3

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

Том
источник
Спасибо, но не очень подходит для 15000+ строк! +1 за рабочую идею, и вам нужен представитель :)
NWS
2

Если записи в порядке,

  1. Разбейте ввод на буквенные и числовые записи, используя grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Соедините два полученных файла alphaи digit, используя paste:

    • paste alpha digit(можно добавить, -d " "чтобы вместо табуляции использовался пробел)
njsg
источник
1
Без временных файлов: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)или с помощью одного процесса замещения: grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956
1

Жаль, что у awk нет хороших функций push / pop / unshift / shift. Вот короткий фрагмент Perl

perl -M5.010 -lne '
  given ($_) {
    when (/^[[:alpha:]]+$/) {push @alpha, $_}
    when (/^\d+$/) {say shift(@alpha), " ", $_}
    default {say}
  }
'
Гленн Джекман
источник
Когда я запускаю его, он выводит дополнительную (ведущую) пустую строку на группу.
Peter.O
Из-за этого defaultпредложения сразу выводятся пустые строки, поэтому перед строкой «AAAA» будет отображаться пробел перед «1234».
Гленн Джекман
0

Дайте файл с текстом, попробуйте использовать prи обработать синтаксис подстановок, как показано ниже:

$ pr -mt <(grep -i "^[a-z]" file.txt) <(grep -i "^[0-9]" file.txt)
AAAA                    1234
BBBB                    5678
CCCC                    9012
DDDD                    3456
EEEE                    7890

Вы можете отрегулировать ширину на -w9или удалить пробелы на sed "s/ //g".

kenorb
источник