Listeyi belirli bir karakterle nasıl hizalayabilirim?


13

Metin satırlarını rastgele bir karakterle yatay olarak hizalamak için kullanabileceğim bir komut veya komutlar kümesi var mı? Örneğin, bir e-posta adresi listesiyle çıktı, tüm '@' karakterlerinin dikey olarak sıralandığı bir metin dosyası oluşturur.

Başarılı olmak için, çoğu satırın başına değişken sayıda boş alanın eklenmesi gerektiğine inanıyorum. Okumak için daha fazla çaba harcadıkları için ayrı sütunlar istemiyorum (örneğin, column -t -s "@" < file.txt).

Önce:

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

Sonra:

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

Başka bir ifadeyle: Çevreleyen metnin etrafında yatay olarak ortalandığı bir bağlantı noktası olarak bir karakter belirtebilir miyim? Bunun için kullanım durumum, görsel olarak daha kolay taranmasını sağlamak için e-posta adresleridir.


1
Birden fazla @sembol varsa ne olmalı ?
Zeta

İyi soru, birden çok @sembol e-posta adresleriyle ilgili bir sorun olmamalı , ancak kullanıcı satır başına bir karakterin hangi örneğinin çevresinde diğer metnin ortalandığı 'çapa' olacağını seçebilmelidir.
Tom Brossman

1
@E-posta adreslerinde birden çok sembole izin verilir, örn tom"@brossmann"@example.com. Bu yüzden birden fazla @sembol varsa ne olması gerektiğini sordum :).
Zeta

@Zeta Çeşitli @e-posta hizmetlerinde birden çok sembole izin verilmez. Ham, filtresiz kullanıcı girişi ile uğraşmıyorsanız, "gerçek" olandan daha sıkı bir standarda uyan "normal" e-postaları beklemek tamamen mantıklıdır, bu durumda no ile satırlarla ilgilenme olasılığınız daha yüksektir @.
Monica'nın Davası

Yanıtlar:


3

HAYIR Awk. Sadece sedve column:

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

Çıktı:

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

Şimdi, düşündüğüm kadarıyla, bu neredeyse Sundeep'in çözümü ile aynı, sadece daha kısa görünüyor / daha az çağrı var sedve @her satırda sadece bir kez gerçekleştiğini varsayar .


1
Daha da kısa olabilir:column -ts@ input.txt | sed -r 's/([^ ]+)( *)\s\s/\2\1@/'
MiniMax

11

En basit haliyle, ilk alanı uygun şekilde geniş bir alan genişliğinde yazdırabilirsiniz, örn.

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

AFAIK, belirli bir maksimum alan genişliğini varsaymayan herhangi bir yöntem için dosyanın bellekte tutulması veya iki geçiş yapılması gerekir.


iyi bir, uzunluk elde etmek için de kullanabilirsiniz cw=$(cut -d@ -f1 file | wc -L)ve sonraawk -v w="$cw" 'BEGIN{OFS=FS="@"} {$1 = sprintf("%*s", w, $1)} 1'
Sundeep

Bunu 328 adres listesinde test ederek, on çıkışta bir şekilde eksik (şimdi 318 satır). Açıklık için koştum 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. Kalanı güzel biçimlendirdi, ancak bazı veriler eksik.
Tom Brossman

1
@TomBrossman teşekkürler Ben sadece oldukça ciddi bir kusuru olduğunu fark ettim - aynı isim alanlarını işlemeyecek - Bunu sileceğim
steeldriver

Aynı sonuç, ama daha kısacaawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax

6

hacky çözümü, giriş metni hakkında çok şey varsayıyor

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

Ayırıcının solundaki tüm dizeleri sağa hizalayan mümkün olan en kısa dolgu uzunluğunu kullanan hızlı bir Python çözümü:

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

Kullanımı:

python3 align-field.py < data.txt

2

Başka bir GNU awk+ columnçözümü:

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

Çıktı:

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

Bunun nasıl çalıştığı hakkında biraz bilgi verebilir misiniz?
Joe

2

Bu, Bash dizesi manipülasyonu ile de çalışabilir.

Bash betiği (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

Sonuç:

   123@example.com
456789@example.net
 01234@something-else.com
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.