Bagaimana cara menyelaraskan daftar ke karakter tertentu?


13

Apakah ada perintah atau serangkaian perintah yang dapat saya gunakan untuk menyelaraskan garis teks secara horizontal ke karakter yang berubah-ubah? Misalnya, dengan daftar alamat email, output akan menghasilkan file teks dengan semua karakter '@' berbaris secara vertikal.

Agar berhasil, saya percaya bahwa sejumlah variabel ruang kosong harus ditambahkan ke awal sebagian besar baris. Saya tidak ingin kolom terpisah karena lebih banyak upaya untuk membaca (misalnya, column -t -s "@" < file.txt).

Sebelum:

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

Setelah:

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

Dengan kata lain: dapatkah saya menentukan karakter sebagai titik jangkar, di mana teks di sekitarnya dipusatkan secara horizontal? Kasus penggunaan saya untuk ini adalah alamat email, untuk membuatnya lebih mudah untuk memindai secara visual.


1
Apa yang harus terjadi jika ada banyak @simbol?
Zeta

Pertanyaan bagus, banyak @simbol seharusnya tidak menjadi masalah dengan alamat email tetapi seorang pengguna harus dapat memilih contoh karakter per baris mana yang akan menjadi 'jangkar' di sekitar mana teks lain dipusatkan.
Tom Brossman

1
Beberapa @simbol diperbolehkan dalam alamat email, mis tom"@brossmann"@example.com. Itu sebabnya saya bertanya apa yang harus terjadi jika ada banyak @simbol :).
Zeta

@Zeta Beberapa @simbol tidak diperbolehkan di berbagai layanan email. Sangat masuk akal untuk mengharapkan email "normal" yang sesuai dengan standar yang lebih ketat daripada yang "asli", kecuali jika Anda berurusan dengan input pengguna yang mentah dan tidak disaring, dalam hal ini Anda lebih mungkin berurusan dengan garis tanpa @.
Dana Gugatan Monica

Jawaban:


3

TIDAK ADA AWK. Hanya seddan column:

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

Keluaran:

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

Sekarang, yang saya pikirkan, ini hampir sama dengan solusi Sundeep, itu hanya terlihat lebih pendek / memiliki lebih sedikit panggilan ke sed, dan juga menganggap itu @terjadi hanya sekali di setiap baris.


1
Ini bisa menjadi lebih singkat:column -ts@ input.txt | sed -r 's/([^ ]+)( *)\s\s/\2\1@/'
MiniMax

11

Paling sederhana, Anda bisa mencetak bidang pertama dalam bidang lebar yang sesuai misalnya

awk -F@ 'BEGIN{OFS=FS} {$1 = sprintf("%12s", $1)} 1' file
         123@example.com
      456789@example.net
       01234@something-else.com

AFAIK metode apa pun yang tidak mengasumsikan bidang lebar maksimum tertentu akan memerlukan memegang file dalam memori atau membuat dua lintasan.


bagus, untuk mendapatkan panjang kita juga bisa menggunakan cw=$(cut -d@ -f1 file | wc -L)dan kemudianawk -v w="$cw" 'BEGIN{OFS=FS="@"} {$1 = sprintf("%*s", w, $1)} 1'
Sundeep

Menguji ini terhadap daftar 328 alamat, sepuluh entah bagaimana hilang dari output (sekarang 318 baris). Untuk lebih jelasnya, saya berlari 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. Itu memformat sisanya dengan baik, tetapi beberapa data hilang.
Tom Brossman

1
@ TomBrossman terima kasih, saya baru sadar ini memiliki cacat yang cukup serius - tidak akan menangani bidang nama yang identik - Saya akan menghapus yang satu itu
steeldriver

Hasil yang sama, tetapi lebih ringkasawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax

6

solusi hacky, mengasumsikan banyak tentang input teks

$ # 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

Solusi Python cepat yang menggunakan panjang padding yang sesingkat mungkin yang meluruskan kanan semua senar kiri pemisah:

#!/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)

Pemakaian:

python3 align-field.py < data.txt

2

Solusi GNU awk+ columnlainnya:

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

Hasil:

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

Bisakah Anda menambahkan sedikit tentang cara kerjanya?
Joe

2

Ini dapat bekerja dengan manipulasi string Bash juga.

Skrip Bash (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

Hasil:

   123@example.com
456789@example.net
 01234@something-else.com
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.