Як вирівняти список до конкретного символу?


13

Чи є команда чи набір команд, які я можу використовувати для горизонтального вирівнювання рядків тексту до довільного символу? Наприклад, зі списком адрес електронної пошти на виході буде створено текстовий файл із усіма символами '@', розташованими вертикально.

Для успіху я вважаю, що змінну кількість порожніх пробілів потрібно додати до початку більшості рядків. Я не хочу, щоб окремі стовпчики, оскільки вони вимагають більше зусиль для читання (наприклад, column -t -s "@" < file.txt).

Перед:

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

Після:

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

По-іншому: чи можу я вказати символ як опорну точку, навколо якої горизонтальний центр розташований навколишній текст? Мій приклад для цього - адреси електронної пошти, щоб полегшити візуальне сканування.


1
Що має відбутися, якщо є кілька @символів?
Зета

Добре запитання, кілька @символів не повинні бути проблемою з адресами електронної пошти, але користувач повинен мати можливість вибрати, який екземпляр символу в рядку буде "якорем", навколо якого зосереджений інший текст.
Том Броссман

1
@У адресах електронної пошти дозволено кілька символів, наприклад tom"@brossmann"@example.com. Тому я запитав, що має статися, якщо є кілька @символів :).
Зета

@Zeta Кілька @символів заборонено в різних електронних службах. Цілком розумно розраховувати на "звичайні" електронні листи, які відповідають більш жорстким стандартам, ніж "справжні", якщо ви не маєте справу з сирим, нефільтрованим вводом користувача, і в цьому випадку ви, швидше за все, матимуть справу з рядками без " @.
Фонд позову Моніки

Відповіді:


3

НЕ Awk. Тільки sedі column:

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

Вихід:

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

Тепер, коли я думаю про це, це майже те саме, що рішення Sundeep ', воно просто виглядає коротше / має менше дзвінків sed, а також передбачає, що @це відбувається лише один раз у кожному рядку.


1
Це може бути ще коротше:column -ts@ input.txt | sed -r 's/([^ ]+)( *)\s\s/\2\1@/'
MiniMax

11

У найпростішому випадку, ви можете просто надрукувати перше поле з відповідно великою шириною поля, наприклад

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

Для будь-якого методу AFAIK, який не передбачає конкретної максимальної ширини поля, буде потрібно або зберегти файл у пам'яті, або зробити два проходи.


хороший, щоб отримати довжину, можна також скористатися, cw=$(cut -d@ -f1 file | wc -L)а потімawk -v w="$cw" 'BEGIN{OFS=FS="@"} {$1 = sprintf("%*s", w, $1)} 1'
Sundeep

Тестуючи це на списку з 328 адрес, десять якимось чином не вистачає у висновку (зараз 318 рядків). Для наочності я побіг 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. Залишок було добре відформатовано, але деякі дані відсутні.
Том Броссман

1
@TomBrossman дякую, що я щойно зрозумів, що він має досить серйозний недолік - він не буде обробляти ідентичні поля імен - я збираюся видалити це
steeldriver

Той самий результат, але більш стислоawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax

6

hacky рішення, передбачає багато про вхідний текст

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

Швидке рішення Python, яке використовує найкоротшу можливу довжину накладки, яка вирівнює право рядки зліва від роздільника:

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

Використання:

python3 align-field.py < data.txt

2

Ще одне рішення GNU awk+ column:

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

Вихід:

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

Чи можете ви додати трохи про те, як працює цей?
Джо

2

Це може працювати і з маніпуляцією з рядком Баша.

Сценарій 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

Результат:

   123@example.com
456789@example.net
 01234@something-else.com
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.