วิธีจัดแนวรายการให้เป็นอักขระเฉพาะ


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
จะเกิดอะไรขึ้นหากมีหลาย@สัญลักษณ์
Zeta

เป็นคำถามที่ดี@สัญลักษณ์หลายอย่างไม่ควรมีปัญหากับที่อยู่อีเมล แต่ผู้ใช้ควรเลือกตัวอย่างของอักขระต่อบรรทัดว่า 'ยึด' ที่มีข้อความอื่นอยู่ตรงกลาง
Tom Brossman

1
หลายสัญลักษณ์ที่ได้รับอนุญาตในที่อยู่อีเมลเช่น@ tom"@brossmann"@example.comนั่นเป็นเหตุผลที่ฉันถามว่าจะเกิดอะไรขึ้นถ้ามี@สัญลักษณ์หลายอัน:)
Zeta

@Zeta @ไม่อนุญาตให้มีหลายสัญลักษณ์ในบริการอีเมลที่หลากหลาย ก็สมควรที่จะคาดหวังทั้งหมดอีเมล "ปกติ" ที่เหมาะสมกับมาตรฐานที่เข้มงวดมากขึ้นกว่า "ของจริง" @หนึ่งจนกว่าคุณจะซื้อขายอยู่กับดิบเข้าของผู้ใช้ที่ไม่ได้กรองซึ่งในกรณีที่คุณมีแนวโน้มที่จะจัดการกับเส้นที่มีไม่มี
คดีฟ้องร้องกองทุนโมนิก้า

คำตอบ:


3

ไม่กลัว เท่านั้น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เพื่อความชัดเจนฉันวิ่ง มันจัดรูปแบบส่วนที่เหลือเป็นอย่างดี แต่ข้อมูลบางอย่างหายไป
Tom Brossman

1
@ TomBrossman ขอบคุณฉันเพิ่งรู้ว่ามันมีข้อบกพร่องร้ายแรงมาก - มันจะไม่จัดการกับฟิลด์ชื่อเหมือนกัน - ฉันจะลบอันนั้น
steeldriver

ผลลัพธ์เดียวกัน แต่มีความรัดกุมมากขึ้นawk -F@ '{printf "%12s@%s\n", $1, $2}' input.txt
MiniMax

6

โซลูชันแฮ็คข้อมูลเกี่ยวกับข้อความที่ป้อนเข้ามามากมาย

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

คุณช่วยเพิ่มเล็กน้อยเกี่ยวกับวิธีการทำงานนี้ได้อย่างไร
Joe

2

สิ่งนี้สามารถทำงานกับการจัดการสตริงของ Bash ได้เช่นกัน

Bash script (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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.