alternativa segura unicode para dobrar

3

Estou usando fold -w 3 para dividir uma linha em vários 3 caracteres, no entanto, com a implementação GNU, ela não funciona para texto com caracteres de múltiplos bytes.

Como posso alcançar o acima com sed ?

Eu criei sed -r 's/^(.{0,3})(.*)/\n/g' , mas isso só faz uma substituição:

echo "111222333444555666" | sed -r 's/^(.{0,3})(.*)/\n/g' 
111
222333444555666

Exemplos adicionais:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | sed -r 's/^(.{0,3})(.*)/\n/g' 
ĄĄĄ
ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ

E fold com o comportamento de corrupção:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | fold -w 3                         
Ą�
�Ą
Ą�
�Ą
Ą�
    
por Chris Stryczynski 07.07.2018 / 19:24

6 respostas

6

Abordagem curta grep :

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | grep -Eo '.{1,3}'
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ

Para reter apenas sequências de 3 caracteres: ... | grep -Eo '.{3}'

    
por 07.07.2018 / 19:55
3

Observe que o problema não é com o conjunto de caracteres Unicode, mas com caracteres codificados em 2 ou mais bytes (assim como caracteres com largura diferente de uma célula).

UTF-8 é uma codificação de Unicode onde os caracteres U + 0080 a U + 10FFFFF são codificados em 2 ou mais bytes. Os caracteres Unicode U + 0000 a U + 007F são os mesmos que em ASCII e em UTF-8 são codificados em um único byte (o mesmo que em ASCII) e não são um problema aqui.

Existem outras codificações do conjunto de caracteres Unicode (como iso8859-1, byte único, mas limitado aos caracteres U + 0000 a U + 00FF ou GB18030, multi-byte), e há outros conjuntos de caracteres não-Unicode com codificações de múltiplos bytes.

Você pode dizer qual codificação de caracteres é usada em sua localidade com o comando locale charmap .

A implementação GNU de fold atualmente só funciona corretamente com caracteres de byte único. O fold da maioria dos outros sistemas não tem esse problema. Muitos podem até manipular caracteres com largura de exibição zero ou dupla.

A implementação de fold do busybox suportou o UTF-8 (não outros charmaps multi-byte) desde 2010.

  • No FreeBSD ou no Solaris:

    $ echo $'a\u0301bcde' | fold -w3
    ábc
    de
    
  • com o busybox fold:

    $ echo $'a\u0301bcde' | busybox fold -w3
    áb
    cde
    
  • com dobra GNU:

    $ echo $'a\u0301bcde' | fold -w3
    á
    bcd
    e
    

U + 0301 é um acento agudo combinando. Ele tem uma largura nula e em UTF-8 é codificado em 2 bytes (0xcc 0x81). Então, esse á ( $'a\u0301' ) é um cluster grafema de largura 1 feito de 2 caracteres codificados em 3 bytes, daí os 3 comportamentos diferentes, o mais correto dos quais é o FreeBSD / Solaris 'aqui.

    
por 06.12.2018 / 18:59
1

Usando sed:

$ echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | sed 's/.../&\n/g'
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ

Ou solução (ões) mais geral (mais fácil de definir o número de caracteres):

sed    's/.\{3\}/&\n/g'             # Using BRE (basic) syntax
sed -E 's/.{3}/&\n/g'               # Using ERE (extended) syntax.
    
por 08.07.2018 / 00:38
0

Encontrou uma solução:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | sed -r 's/(.{0,3}){1}/&\n/g' 
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
    
por 07.07.2018 / 19:34
0

Só porque ...

$ echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | gawk '{$1=$1} 1' FPAT=".{,3}" OFS="\n"
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ
    
por 08.07.2018 / 01:20
0

Aqui está uma solução POSIX:

awk '{gsub(/.{5}/, "&\n")} 1'

Curiosamente, a solução Awk tem mais desempenho que dobra.

link

    
por 08.07.2018 / 02:21

Tags