Como alinhar a lista ao caractere específico?

13

Existe um comando ou conjunto de comandos que eu possa usar para alinhar linhas de texto horizontalmente a um caractere arbitrário? Por exemplo, com uma lista de endereços de e-mail, a saída produziria um arquivo de texto com todos os caracteres '@' alinhados verticalmente.

Para ter sucesso, acredito que um número variável de espaços vazios deve ser adicionado ao início da maioria das linhas. Não quero colunas separadas, pois elas exigem mais esforço para ler (por exemplo, column -t -s "@" < file.txt ).

Antes:

[email protected]
[email protected]
[email protected]

Depois:

   [email protected]
[email protected]
 [email protected]

Colocando de forma diferente: posso especificar um caractere como um ponto de ancoragem, em torno do qual o texto ao redor é centralizado horizontalmente? Meu caso de uso para isso é o endereço de e-mail, para facilitar a verificação visual.

    
por Tom Brossman 10.12.2017 / 14:51

6 respostas

3

NÃO Awk. Apenas sed e column :

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

Saída:

   [email protected]
[email protected]
 [email protected]

Agora, penso nisso, isso é quase o mesmo que a solução Sundeep, ele parece mais curto / tem menos chamadas para sed e também assume que @ acontece apenas uma vez em cada linha.

    
por 10.12.2017 / 17:04
11

Na sua forma mais simples, você poderia imprimir o primeiro campo em uma largura de campo adequadamente grande, por exemplo,

awk -F@ 'BEGIN{OFS=FS} {$1 = sprintf("%12s", $1)} 1' file
         [email protected]
      [email protected]
       [email protected]

AFAIK qualquer método que não assuma uma largura de campo máxima específica exigirá que você mantenha o arquivo na memória ou faça duas passagens.

    
por 10.12.2017 / 15:44
6

solução hacky, assume muito sobre o texto de entrada

$ # 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/^([^ ]+)( +)//'
     [email protected]
  [email protected]
   [email protected]
    
por 10.12.2017 / 15:17
4

Uma solução rápida em Python que usa o comprimento de preenchimento mais curto possível que alinha à direita todas as sequências do separador:

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

Uso:

python3 align-field.py < data.txt
    
por 11.12.2017 / 10:29
2

Outra solução GNU awk + column :

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

A saída:

   [email protected]
[email protected]
 [email protected]
    
por 10.12.2017 / 16:45
2

Isso também funciona com a manipulação de strings Bash.

Script de 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

O resultado:

   [email protected]
[email protected]
 [email protected]
    
por 11.12.2017 / 05:19