Comment fusionner le texte des lignes alphabétiques avec les lignes numériques dans le shell?


10

J'ai un fichier contenant du texte comme celui-ci:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

etc...

Et je veux faire correspondre les lignes alphabétiques avec les lignes numériques afin qu'elles soient comme ceci:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Quelqu'un connaît-il un moyen simple d'y parvenir?


Vous mentionnez emacs.. Êtes-vous à la recherche d'une elispsolution, ou comment exécuter un shell-script depuis emacs?
Peter

Réponses:


3

À sens unique en utilisant perl:

Contenu 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 ];
}

Contenu de infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Exécutez-le comme:

perl script.pl infile

Et résultat:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890

Intéressant ... Vos deux lignes de substitution regex qui Supprimer les espaces avant et arrière courent 1,6 fois plus rapide qu'une seule ligne qui utilise et non les références arrières gourmands: s/\A\s*(.*?)\s*\Z/\1/.
Peter.O

4

Dans awk, en préservant les lignes vides, en supposant que le fichier est bien formaté, mais une logique pourrait être ajoutée pour vérifier le fichier:

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

ou, en une seule étape, sans fichiers temporaires

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

La dernière sedétape supprime le délimiteur sur les lignes vides, qui est introduit par paste...


3

Avec emacs, utilisez les opérations de rectangle pour couper les lignes de texte et collez-les avant les lignes numériques.


Merci, mais pas vraiment adapté pour plus de 15 000 lignes! + 1 pour une idée de travail et vous avez besoin du représentant :)
NWS

2

Si les entrées sont en ordre,

  1. Divisez l'entrée en entrées alphabétiques et numériques, en utilisant grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Joignez les deux fichiers résultants alphaet digit, en utilisant paste:

    • paste alpha digit(vous pouvez l'ajouter -d " "pour qu'il utilise un espace au lieu d'un onglet)

1
Sans fichiers temporaires: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)ou avec une seule substitution de processus: grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956

1

Dommage que awk n'ait pas de belles fonctions push / pop / unshift / shift. Voici un court extrait de Perl

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

Lorsque je l'exécute, il génère une ligne vierge supplémentaire (principale) par groupe.
Peter.O

En raison de la defaultclause, les lignes vierges sont immédiatement imprimées, donc le blanc avant "1234" s'affichera avant la ligne "AAAA".
glenn jackman

0

Donnez un fichier avec du texte, essayez d'utiliser pret de traiter la syntaxe de substitution comme ci-dessous:

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

Vous pouvez ajuster la largeur -w9ou supprimer les espaces par sed "s/ //g".

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.