Wie kann ich die Liste auf ein bestimmtes Zeichen ausrichten?

13

Gibt es einen Befehl oder eine Reihe von Befehlen, mit denen ich Textzeilen an einem beliebigen Zeichen horizontal ausrichten kann? Bei einer Liste von E-Mail-Adressen würde die Ausgabe beispielsweise eine Textdatei mit allen vertikal angeordneten '@'-Zeichen erzeugen.

Um erfolgreich zu sein, muss am Anfang der meisten Zeilen eine variable Anzahl von Leerzeichen eingefügt werden. Ich möchte keine separaten Spalten, da das Lesen von ihnen mehr Aufwand erfordert (z. B. column -t -s "@" < file.txt).

Vor:

[email protected]
[email protected]
[email protected]

Nach:

   [email protected]
[email protected]
 [email protected]

Anders ausgedrückt: Kann ich ein Zeichen als Ankerpunkt angeben, um den der umgebende Text horizontal zentriert ist? Mein Anwendungsfall hierfür sind E-Mail-Adressen, um das visuelle Scannen zu vereinfachen.

Tom Brossman
quelle
1
Was soll passieren, wenn mehrere @Symbole vorhanden sind ?
Zeta
Gute Frage, mehrere @Symbole sollten kein Problem mit E-Mail-Adressen sein, aber ein Benutzer sollte in der Lage sein, die Instanz eines Zeichens pro Zeile als "Anker" auszuwählen, um den der andere Text zentriert ist.
Tom Brossman
1
@In E-Mail-Adressen sind mehrere Symbole zulässig, z tom"@brossmann"@example.com. Deshalb habe ich gefragt, was passieren soll, wenn es mehrere @Symbole gibt :).
Zeta
@Zeta Mehrere @Symbole sind in einer Vielzahl von E-Mail-Diensten nicht zulässig. Es ist völlig vernünftig, "normale" E-Mails zu erwarten, die einem strengeren Standard entsprechen als die "echten", es sei denn, Sie haben es mit rohen, ungefilterten Benutzereingaben zu tun @.
Fund Monica's Lawsuit

Antworten:

3

NEIN Awk. Nur sedund column:

column -ts@ file.txt | sed -E 's/([^ ]+)([ ]+) (.+)/\2\1@\3/'

Ausgabe:

   [email protected]
[email protected]
 [email protected]

Nun, ich denke darüber nach, das ist fast das Gleiche wie die Lösung von Sundeep, sie sieht nur kürzer aus / hat weniger Anrufe sedund es wird auch angenommen, dass @dies in jeder Zeile nur einmal vorkommt.

wvxvw
quelle
1
Es kann noch kürzer sein:column -ts@ input.txt | sed -r 's/([^ ]+)( *)\s\s/\2\1@/'
MiniMax
11

Im einfachsten Fall können Sie einfach das erste Feld in einer angemessen großen Feldbreite drucken, z

awk -F@ 'BEGIN{OFS=FS} {$1 = sprintf("%12s", $1)} 1' file
         [email protected]
      [email protected]
       [email protected]

AFAIK Für jede Methode, die keine bestimmte maximale Feldbreite annimmt, muss die Datei entweder im Speicher gehalten oder zwei Durchgänge ausgeführt werden.

Stahlfahrer
quelle
gut, um Länge zu bekommen kann man auch benutzen cw=$(cut -d@ -f1 file | wc -L)und dannawk -v w="$cw" 'BEGIN{OFS=FS="@"} {$1 = sprintf("%*s", w, $1)} 1'
Sundeep
Wenn man dies mit einer Liste von 328 Adressen vergleicht, fehlen irgendwie zehn in der Ausgabe (jetzt 318 Zeilen). Aus Gründen der Übersichtlichkeit rannte ich los awk -F@ '{a[$1] = $2; w = length($1) > w? length($1) : w; next} END {for (i in a) printf("%*s%c%s\n", w, i, FS, a[i])}' INPUT-FILE.txt > OUT.txt. Der Rest wurde gut formatiert, aber einige Daten fehlen.
Tom Brossman
1
@TomBrossman Dank , den ich gerade erkennen , dass es durchaus einen ernsten Fehler hat - es wird nicht identisch Namensfelder behandeln - ich werde , dass man löschen
steeldriver
Das gleiche Ergebnis, aber prägnanterawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax
6

hackige Lösung, setzt viel über Eingabetext voraus

$ # four commas to reduce chance of it affecting actual email address
$ sed 's/@/,,,,@/' ip.txt | column -t -s,,,,
123     @example.com
456789  @example.net
01234   @something-else.com

$ sed 's/@/,,,,@/' ip.txt | column -t -s,,,, | sed -E 's/^([^ ]+)( +)/\2\1/'
     [email protected]
  [email protected]
   [email protected]
Sundeep
quelle
4

Eine schnelle Python-Lösung, die die kürzestmögliche Abstandslänge verwendet und alle Zeichenfolgen links vom Trennzeichen rechts ausrichtet:

#!/usr/bin/env python3
import sys
fieldsep = '@'
records = [line.rstrip('\n').split(fieldsep, 1) for line in sys.stdin]
col1_len = max((len(r[0]) for r in records), default=0)
for r in records:
    print(r[0].rjust(col1_len), r[1], sep=fieldsep)

Verwendung:

python3 align-field.py < data.txt
David Foerster
quelle
2

Eine andere GNU awk+ column-Lösung:

awk '{ split($0,a,/ +/,sep); printf "%*s@%s\n",length($1 sep[1])-2,$1,$2 }' <(column -ts'@' file)

Die Ausgabe:

   [email protected]
[email protected]
 [email protected]
RomanPerekhrest
quelle
Könntest du ein bisschen dazu sagen, wie das hier funktioniert?
Joe
2

Dies kann auch mit der Manipulation von Bash-Strings funktionieren.

Bash-Skript (4.x):

#!/bin/bash

read -d '' -r -a data <"data.txt"

for ((pos=0, i=0; i<${#data[@]}; i++)); do
    locl=${data[$i]%@*}                         # The local-part.
    [[ ${#locl} -gt $pos ]] && pos=${#locl}     # Determine the lengthiest $locl.
done

for ((i=0; i<${#data[@]}; i++)); do
    email=${data[$i]}
    locl=${email%@*}                            # The local-part.
    domain=${email#*@}                          # The email domain.
    printf '%*s@%s\n' $pos $locl $domain        # Align $locl to the right, at $pos.
done

Das Ergebnis:

   [email protected]
[email protected]
 [email protected]
zero2cx
quelle