如何将列表与特定字符对齐?


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

很好的问题是,多个@符号不应成为电子邮件地址的问题,但用户应该能够选择每行字符的哪个实例作为其他文本居中的“锚点”。
汤姆·布鲁斯曼

1
@电子邮件地址中允许使用多个符号,例如tom"@brossmann"@example.com。这就是为什么我问如果有多个@符号,该怎么办:)。
Zeta

@Zeta @各种电子邮件服务中均不允许使用多个符号。期望“正常”电子邮件比“真实”电子邮件更严格的标准是完全合理的,除非您要处理未经过滤的原始用户输入,在这种情况下,您更有可能处理no的行@
基金莫妮卡的诉讼

Answers:


3

没有啊 仅sedcolumn

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字符串操作一起使用。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.