Jak scalić tekst linii alfabetycznych z liniami numerycznymi w powłoce?

10

Mam plik z takim tekstem:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

itp...

Chcę dopasować linie alfabetyczne do linii numerycznych, aby wyglądały tak:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Czy ktoś zna prosty sposób na osiągnięcie tego?

NWS
źródło
Wspominasz emacs... Szukasz elisprozwiązania lub jak uruchomić skrypt powłoki z poziomu emacsa?
Peter.O
W Vimie: Scal wiele linii (dwa bloki) w SO
kenorb

Odpowiedzi:

3

Jeden sposób przy użyciu perl:

Treść 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 ];
}

Treść infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Uruchom to jak:

perl script.pl infile

I wynik:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890
Birei
źródło
Ciekawe ... Twoje dwie linie regex substytucji który Usuwanie spacji początkowych i końcowych prowadzone około 1,6 razy szybciej niż jednej linii, który wykorzystuje backreferencing i nie chciwy: s/\A\s*(.*?)\s*\Z/\1/.
Peter.O
4

W awk, zachowując puste linie, zakładając, że plik jest dobrze sformatowany, ale można dodać logikę, aby sprawdzić plik:

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
źródło
4
<input sed -nr '/^[A-Z]{4}$/,/^$/w out1
                /^[0-9]{4}$/,/^$/w out2'
paste -d' ' out1 out2 |sed 's/^ $//' 

lub w jednym kroku, bez plików tymczasowych

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

Ostatni sedkrok usuwa separator w pustych liniach, który wprowadza paste...

Peter.O
źródło
3

Za pomocą emacsa użyj operacji prostokąta, aby wyciąć linie tekstu i wkleić je przed liniami numerycznymi.

Tomek
źródło
Dzięki, ale tak naprawdę nie nadaje się na ponad 15000 linii! + 1 za działający pomysł i potrzebujesz przedstawiciela :)
NWS
2

Jeśli wpisy są w porządku,

  1. Podziel dane wejściowe na pozycje alfabetyczne i numeryczne, używając grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Połącz dwa powstałe pliki alphai digitużywając paste:

    • paste alpha digit(możesz dodać, -d " "aby używała spacji zamiast tabulacji)
njsg
źródło
1
Bez plików tymczasowych: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)albo z jednego substytucji procesowej: grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956
1

Szkoda, że ​​awk nie ma ładnych funkcji push / pop / unshift / shift. Oto krótki fragment Perla

perl -M5.010 -lne '
  given ($_) {
    when (/^[[:alpha:]]+$/) {push @alpha, $_}
    when (/^\d+$/) {say shift(@alpha), " ", $_}
    default {say}
  }
'
Glenn Jackman
źródło
Po uruchomieniu generuje dodatkową (wiodącą) pustą linię na grupę.
Peter.O
Ze względu na defaultklauzulę puste linie są natychmiast drukowane, więc puste przed „1234” pojawią się przed linią „AAAA”.
glenn jackman
0

Podaj plik z tekstem, spróbuj użyć pri przetworz składnię podstawień jak poniżej:

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

Możesz dostosować szerokość o -w9lub usunąć spacje o sed "s/ //g".

kenorb
źródło