Como posso dividir as letras de uma palavra, com cada uma das últimas quatro letras em uma linha?

2

Como posso dividir as letras de uma palavra e entre um único espaço, com cada uma das quatro últimas letras em uma linha? Por exemplo, Dado,

 1. placing
 2. backtick
 3. paragraphs

Eu gostaria de ver abaixo

 1. pla cing
 2. back tick
 3. pa ragr aphs
    
por Prasannakumar Merugu 08.08.2017 / 12:05

4 respostas

1

Solução

awk :

awk '{ c=0; for(i=length($2);i>0;i-=4) {a[++c]=(i-4>0)? substr($2,i-4+1,4) : substr($2,1,i)} 
    $2=""; for(i=length(a);i>0;i--) $2=$2 FS a[i] }1' file

A saída:

1.  pla cing
2.  back tick
3.  pa ragr aphs
    
por 08.08.2017 / 14:36
1

Com Perl usando lookarounds , poderíamos executar a operação como:

perl -pe 's/(?<=\w)(?=(?:\w{4})+$)/ /g'

Que se traduz como: quando em pé em uma posição, à nossa esquerda é um alfanumérico e à nossa direita são pelo menos 4 alnums ou múltiplos dos mesmos até o final da string. Quando tal posição existe, um espaço é colocado lá. Fazer isso afeta globalmente a mudança solicitada.

Poderíamos usar bash para fazer isso também:

#!/bin/bash

# symbolic constants
NL=$'2'; # newline
SP=$'0'; # space

# elementary regexes
alnum='[0-9a-zA-Z]'; # a single alphanumeric
alnums4=$(csh -c 'repeat 4 echo -n "$1"' "$alnum"); # 4 consecutive alnums

# main processing
while IFS= read -r line res; do
   while c4=$(expr "$SP$line$NL" : ".*$alnum\($alnums4\)$NL")
   do
      res=${c4}${res:+"$SP"}${res-} line=${line%????}
   done
   printf '%s %s\n' "$line" "$res"
done

Usando o editor GNU sed :

sed -Ee '
   s/\S+/\n&\n/2; # enclose the 2nd field with markers

   # a do-while loop to progessively move the right marker to the left,
   # consuming 4 alnums in each iteration. Looping stops when 4 alnums+
   # 1 alnum at the boundary remains.
   :loop
      s/(\n[[:alnum:]].*)([[:alnum:]]{4})\n/\n /
   tloop

   # clear out the markers when done
   s/\n//g
'
    
por 08.08.2017 / 17:26
1

Com sed , você pode fazer algo como:

sed '
  G
  :1
      s/\([[:alpha:]]\)\([[:alpha:]]\{4\}\)\(\n\)/ /
  t1
  s/\n//
'

Usamos um caractere de nova linha como um marcador em execução (nova linha é o caractere que não aparecerá dentro do espaço de padrão inicial). Nós adicionamos no final inicialmente. Então, enquanto encontrarmos ABCDE<marker> (onde ABCDE são 5 caracteres alfabéticos, você pode substituir [[:space:]] por [^[:blank:]] se você quiser considerar palavras como sequências de não-brancos ao invés de seqüências de letras), nós o substituímos com A<marker> BCDE e loop. E nós removemos o marcador no final.

Dessa forma, temos certeza de processar apenas a palavra que está no final da linha apenas.

Se você quisesse quebrar cada palavra, não apenas a última palavra, seria mais simples:

sed -e :1 -e 's/\(.*[[:alpha:]]\)\([[:alpha:]]\{4\}\)/ /;t1'

Se a sua entrada contiver caracteres decompostos (como na saída de printf 'abcd\u00e9e\u0301f\n' : abcdééf ), você poderá fazer:

perl -Mopen=locale -lpe 'while(s/.*(?=\w)\X\K(?:(?=\w)\X){4}/ $&/){}'
    
por 08.08.2017 / 12:39
1

Usando o Perl (e assumindo apenas caracteres de byte único):

perl -ne 'print scalar(reverse join " ", (reverse =~ /.{1,4}/g)), "\n"'
  • O reverse interno inverte a palavra dada (na verdade, toda a linha de entrada, independentemente do conteúdo).
  • A expressão regular dividirá a palavra invertida em pedaços de quatro caracteres (o último bloco, desde o início da palavra original, pode conter menos caracteres).
  • O join unirá esses fragmentos em uma string, mas com espaços intermediários.
  • O% outer reverse inverte a string unida.
  • O scalar é usado para forçar o reverse externo a operar em contexto escalar.
  • O print produzirá o resultado.

O código abaixo faz a mesma coisa, mas acaba com scalar , "\n" e print usando -p , -l e atribuindo a $_ :

perl -lpe '$_ = reverse join " ", reverse =~ /.{1,4}/g'
    
por 08.08.2017 / 12:38