Làm thế nào để sắp xếp danh sách để nhân vật cụ thể?


13

Có một lệnh hoặc tập hợp các lệnh mà tôi có thể sử dụng để sắp xếp các dòng văn bản theo chiều ngang với một ký tự tùy ý không? Ví dụ: với danh sách các địa chỉ email, đầu ra sẽ tạo ra một tệp văn bản với tất cả các ký tự '@' được xếp theo chiều dọc.

Để thành công tôi tin rằng một số lượng không gian trống khác nhau phải được thêm vào đầu của hầu hết các dòng. Tôi không muốn các cột riêng biệt vì chúng cần nhiều nỗ lực hơn để đọc (ví dụ column -t -s "@" < file.txt:).

Trước:

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

Sau:

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

Đặt khác nhau: tôi có thể chỉ định một ký tự là một điểm neo, xung quanh đó văn bản xung quanh được căn giữa theo chiều ngang không? Trường hợp sử dụng của tôi cho điều này là địa chỉ email, để làm cho chúng dễ dàng quét trực quan hơn.


1
Điều gì sẽ xảy ra nếu có nhiều @biểu tượng?
Zeta

Câu hỏi hay, nhiều @biểu tượng không phải là vấn đề với địa chỉ email nhưng người dùng sẽ có thể chọn phiên bản nào của một ký tự trên mỗi dòng để làm 'neo' xung quanh mà văn bản khác được căn giữa.
Tom Brossman

1
Nhiều @biểu tượng được cho phép trong địa chỉ email, ví dụ tom"@brossmann"@example.com. Đó là lý do tại sao tôi hỏi điều gì sẽ xảy ra nếu có nhiều @biểu tượng :).
Zeta

@Zeta Nhiều @biểu tượng không được phép trong nhiều dịch vụ email. Hoàn toàn hợp lý khi mong đợi các email "bình thường" phù hợp với tiêu chuẩn chặt chẽ hơn so với email "thực", trừ khi bạn đang xử lý dữ liệu đầu vào của người dùng thô, chưa được lọc, trong trường hợp bạn có nhiều khả năng xử lý các dòng không có @.
Vụ kiện của Quỹ Monica

Câu trả lời:


3

KHÔNG Awk. Chỉ sedcolumn:

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

Đầu ra:

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

Bây giờ, tôi nghĩ về điều này, nó gần giống như giải pháp của Sundeep, nó chỉ trông ngắn hơn / có ít cuộc gọi hơn sedvà nó cũng cho rằng điều đó @chỉ xảy ra một lần trong mỗi dòng.


1
Nó có thể còn ngắn hơn nữa:column -ts@ input.txt | sed -r 's/([^ ]+)( *)\s\s/\2\1@/'
MiniMax

11

Đơn giản nhất, bạn chỉ có thể in trường đầu tiên trong một băng thông trường lớn phù hợp, vd

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

AFAIK bất kỳ phương pháp nào không giả định băng thông trường tối đa cụ thể sẽ yêu cầu giữ tệp trong bộ nhớ hoặc thực hiện hai lần.


tốt, để có được chiều dài, người ta cũng có thể sử dụng cw=$(cut -d@ -f1 file | wc -L)và sau đóawk -v w="$cw" 'BEGIN{OFS=FS="@"} {$1 = sprintf("%*s", w, $1)} 1'
Sundeep

Kiểm tra điều này dựa trên danh sách gồm 328 địa chỉ, mười địa chỉ bị thiếu từ đầu ra (hiện có 318 dòng). Để rõ ràng, tôi chạy 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. Nó đã định dạng phần còn lại độc đáo, nhưng một số dữ liệu bị thiếu.
Tom Brossman

1
@TomBrossman cảm ơn tôi mới nhận ra nó có một lỗ hổng khá nghiêm trọng - nó sẽ không xử lý các trường tên giống hệt nhau - Tôi sẽ xóa cái đó
Steeldo

Kết quả tương tự, nhưng chính xác hơnawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax

6

giải pháp hacky, giả định rất nhiều về văn bản đầu vào

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

Một giải pháp Python nhanh sử dụng độ dài đệm ngắn nhất có thể, căn phải tất cả các chuỗi bên trái của dấu phân cách:

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

Sử dụng:

python3 align-field.py < data.txt

2

Một giải pháp GNU awk+ khác column:

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

Đầu ra:

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

Bạn có thể thêm một chút về cách thức hoạt động của cái này không?
Joe

2

Điều này cũng có thể làm việc với thao tác chuỗi Bash.

Tập lệnh 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

Kết quả:

   123@example.com
456789@example.net
 01234@something-else.com
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.