¿Cómo fusionar texto de líneas alfabéticas con líneas numéricas en shell?


10

Tengo un archivo que tiene un texto como este:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

etc ...

Y quiero hacer coincidir las líneas alfabéticas con las líneas numéricas para que sean así:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

¿Alguien sabe de una manera simple de lograr esto?


Usted menciona emacs... ¿Está buscando una elispsolución o cómo ejecutar un script de shell desde emacs?
Peter.O

Respuestas:


3

Una forma de usar perl:

Contenido de 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 ];
}

Contenido de infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Ejecútalo como:

perl script.pl infile

Y resultado:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890

Interesantes ... Sus dos líneas de sustitución de expresiones regulares, que Quitar los espacios iniciales y finales se ejecutan alrededor de 1,6 veces más rápido que una sola línea que utiliza backreferencing y no expansivo: s/\A\s*(.*?)\s*\Z/\1/.
Peter.O

4

En awk, preservar las líneas vacías, suponiendo que el archivo esté bien formateado, pero se podría agregar lógica para verificar el archivo:

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, en un solo paso, sin archivos temporales

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

El último sedpaso elimina el delimitador en las líneas en blanco, que es introducido por paste...


3

Con emacs use operaciones de rectángulo para cortar las líneas de texto y pegarlas antes de las líneas numéricas.


¡Gracias, pero no es realmente adecuado para más de 15000 líneas! + 1 para una idea funcional y necesitas el representante :)
NWS

2

Si las entradas están en orden,

  1. Divida la entrada en entradas alfabéticas y entradas numéricas, usando grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Une los dos archivos resultantes alphay digit, usando paste:

    • paste alpha digit(puede agregar -d " "para que use un espacio en lugar de una pestaña)

1
Sin archivos temporales: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)o con una única sustitución de proceso: grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956

1

Lástima que awk no tenga buenas funciones push / pop / unshift / shift. Aquí hay un pequeño fragmento de Perl

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

Cuando lo ejecuto, genera una línea en blanco adicional (principal) por grupo.
Peter.O

Debido a la defaultcláusula, las líneas en blanco se imprimen inmediatamente, por lo que el espacio en blanco antes de "1234" se mostrará antes de la línea "AAAA".
Glenn Jackman

0

Proporcione un archivo con texto, intente usar pry procese la sintaxis de sustituciones como se muestra a continuación:

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

Puede ajustar el ancho -w9o eliminar espacios mediante sed "s/ //g".

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.