Come unire il testo delle linee alfabetiche con le linee numeriche nella shell?


10

Ho un file con testo come questo:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

eccetera...

E voglio abbinare le linee alfabetiche con le linee numeriche in modo che siano così:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Qualcuno sa un modo semplice per raggiungere questo obiettivo?


Hai detto emacs.. Stai cercando una elispsoluzione o come eseguire uno script di shell da emacs?
Peter

Risposte:


3

Un modo usando perl:

Contenuto di 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 ];
}

Contenuto di infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Eseguilo come:

perl script.pl infile

E risultato:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890

Interessante ... I due linee di sostituzione regex che Rimuovere gli spazi iniziali e finali gestiscono circa 1,6 volte più veloce di una sola riga che utilizza riferimento all'indietro e non avido: s/\A\s*(.*?)\s*\Z/\1/.
Peter

4

In awk, preservando le righe vuote, supponendo che il file sia ben formattato, ma è possibile aggiungere la logica per controllare il file:

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/^ $//' 

o, in un solo passaggio, senza file temporanei

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

L'ultimo sedpassaggio rimuove il delimitatore sulle righe vuote, introdotto da paste...


3

Con emacs usa le operazioni di rettangolo per tagliare le linee di testo e incollarle prima delle linee numeriche.


Grazie, ma non adatto per oltre 15000 linee! + 1 per un'idea di lavoro e hai bisogno del rappresentante :)
NWS

2

Se le voci sono in ordine,

  1. Dividi l'input in voci alfabetiche e voci numeriche, usando grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Unire i due file risultanti alphae digit, usando paste:

    • paste alpha digit(puoi aggiungere in -d " "modo che utilizzi uno spazio anziché una scheda)

1
Senza file temporanei: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)o con una sola sostituzione di processo: grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956,

1

Peccato che Awk non abbia buone funzioni push / pop / unshift / shift. Ecco un breve frammento di Perl

perl -M5.010 -lne '
  given ($_) {
    when (/^[[:alpha:]]+$/) {push @alpha, $_}
    when (/^\d+$/) {say shift(@alpha), " ", $_}
    default {say}
  }
'

Quando lo eseguo, genera una riga vuota (iniziale) aggiuntiva per gruppo.
Peter

A causa della defaultclausola, le righe vuote vengono immediatamente stampate, quindi lo spazio vuoto prima di "1234" verrà visualizzato prima della riga "AAAA".
Glenn Jackman,

0

Dai il file con il testo, prova a usare pred elabora la sintassi delle sostituzioni come di seguito:

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

È possibile regolare la larghezza di -w9o rimuovere gli spazi di sed "s/ //g".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.