Wie füge ich Text aus alphabetischen Zeilen mit den numerischen Zeilen in der Shell zusammen?

10

Ich habe eine Datei mit folgendem Text:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

etc...

Und ich möchte die alphabetischen Linien mit den numerischen Linien abgleichen, damit sie so aussehen:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Kennt jemand einen einfachen Weg, um dies zu erreichen?

NWS
quelle
Sie erwähnen emacs.. Suchen Sie nach einer elispLösung oder wie Sie ein Shell-Skript in Emacs ausführen können?
Peter.O

Antworten:

3

Ein Weg mit perl:

Inhalt von 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 ];
}

Inhalt von infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Führen Sie es wie folgt aus:

perl script.pl infile

Und Ergebnis:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890
Birei
quelle
Interessant ... Ihre beiden Regex-Substitutionszeilen, die führende und nachfolgende Leerzeichen entfernen, werden etwa 1,6-mal schneller ausgeführt als eine einzelne Zeile, die Rückreferenzierung verwendet und nicht gierig ist : s/\A\s*(.*?)\s*\Z/\1/.
Peter.O
4

Unter awkBeibehaltung leerer Zeilen unter der Annahme, dass die Datei gut formatiert ist, kann jedoch eine Logik hinzugefügt werden, um die Datei zu überprüfen:

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

oder in einem einzigen Schritt ohne temporäre Dateien

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

Der letzte sedSchritt entfernt das Trennzeichen in den Leerzeilen, das durch paste...

Peter.O
quelle
3

Verwenden Sie bei Emacs Rechteckoperationen , um die Textzeilen auszuschneiden und vor den numerischen Zeilen einzufügen.

Tom
quelle
Danke, aber nicht wirklich geeignet für mehr als 15000 Zeilen! + 1 für eine Arbeitsidee und du brauchst den Repräsentanten :)
NWS
2

Wenn die Einträge in Ordnung sind,

  1. Teilen Sie die Eingabe in alphabetische und numerische Einträge auf, indem Sie Folgendes verwenden grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Verbinden Sie die beiden resultierenden Dateien alphaund digitverwenden Sie paste:

    • paste alpha digit(Sie können hinzufügen, -d " "damit ein Leerzeichen anstelle einer Registerkarte verwendet wird.)
njsg
quelle
1
Ohne temporäre Dateien: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)oder mit einer einzigen Prozessersetzung : grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956
1

Schade, dass awk keine netten Push / Pop / Unshift / Shift-Funktionen hat. Hier ist ein kurzer Perl-Ausschnitt

perl -M5.010 -lne '
  given ($_) {
    when (/^[[:alpha:]]+$/) {push @alpha, $_}
    when (/^\d+$/) {say shift(@alpha), " ", $_}
    default {say}
  }
'
Glenn Jackman
quelle
Wenn ich es ausführe, wird pro Gruppe eine zusätzliche (führende) Leerzeile ausgegeben.
Peter.O
Aufgrund der defaultKlausel werden Leerzeilen sofort gedruckt, sodass die Leerzeichen vor "1234" vor der Zeile "AAAA" angezeigt werden.
Glenn Jackman
0

Geben Sie eine Datei mit Text ein, versuchen Sie, die prSubstitutionssyntax wie folgt zu verwenden und zu verarbeiten:

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

Sie können die Breite um anpassen -w9oder Leerzeichen um entfernen sed "s/ //g".

Kenorb
quelle