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?


Wspominasz emacs... Szukasz elisprozwiązania lub jak uruchomić skrypt powłoki z poziomu emacsa?
Peter.O

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

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

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...


3

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


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)

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}
  }
'

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".

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.