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:

123@example.com
456789@example.net
01234@something-else.com

Nach:

   123@example.com
456789@example.net
 01234@something-else.com

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.


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:

   123@example.com
456789@example.net
 01234@something-else.com

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.


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
         123@example.com
      456789@example.net
       01234@something-else.com

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.


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/'
     123@example.com
  456789@example.net
   01234@something-else.com

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

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:

   123@example.com
456789@example.net
 01234@something-else.com

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:

   123@example.com
456789@example.net
 01234@something-else.com
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.