Eu tenho um monte de arquivos txt, gostaria de apresentá-los em letras minúsculas, apenas alfabéticos e uma palavra por linha, posso fazê-lo com vários tr
comandos em um pipeline como este:
tr -d '[:punct:]' <doyle_sherlock_holmes.txt | tr '[:upper:]' '[:lower:]' | tr ' ' '\n'
É possível fazer isso em uma varredura? Eu poderia escrever um programa em C para fazer isso, mas eu sinto que há uma maneira de fazê-lo usando tr
, sed
, awk
ou perl
.
Respostas:
Você pode combinar várias traduções (exceto casos complexos que envolvem conjuntos dependentes de localidade sobrepostos), mas não é possível combinar exclusão com tradução.
tr
É provável que duas chamadas sejam mais rápidas que uma única chamada para ferramentas mais complexas, mas isso depende muito do tamanho da entrada, das proporções de caracteres diferentes, da implementaçãotr
e das ferramentas concorrentes, do sistema operacional, do número de núcleos, etc.fonte
tr -s '[:upper:] [:punct:]' '[:lower:]\n' <doyle_sherlock_holmes.txt
printf 'A.AAAA,A' | tr -s '[:upper:] [:punct:]' '[:lower:][\n*]'
getsa\na\na'
, e a transformação para... '[:lower:]\n'
pode não necessariamente fazer absolutamente nada'[:punct:]'
- algunstr
s truncarão set1 para corresponder a 2 e outros farão um implícito[\n*]
. É melhor apenas usar o alcance lá.Aqui estão algumas abordagens:
GNU
grep
etr
: encontre todas as palavras e as minúsculasGNU grep e perl: como acima, mas o perl manipula a conversão para minúsculas
perl: encontre todos os caracteres alfabéticos e imprima-os em letras minúsculas (obrigado @steeldriver):
sed: remova todos os caracteres que não são alfabéticos ou espaços, substitua todos os caracteres alfabéticos por suas versões em minúsculas e substitua todos os espaços por novas linhas. Observe que isso pressupõe que todo espaço em branco seja espaços, sem guias.
fonte
perl -lne 'print lc for /[[:alpha:]]+/g'
também funcionaria? ou é estilo pobre? (Eu sou novo para Perl e tentando aprender!)sed -z 's/\W*\(\w\+\)\W*/\L\1\n/g'
sed
pode fazer\w
agora? Legal!sed
a-z
opção de delimitação de ero do GNU - ele passa por\0NUL
s em vez de novas linhas. Muito legal quando você faz algo comotar -c . | tr -s \\0 | sed -z ...
- mas meio lento.Sim. Você pode fazer isso com
tr
um código de idioma ASCII (que é, para um GNU detr
qualquer maneira, uma espécie de sua única competência) . Você pode usar as classes POSIX ou pode referenciar os valores de bytes de cada caractere pelo número octal. Você também pode dividir as transformações entre os intervalos.O comando acima transforma todos os caracteres em maiúsculas em minúsculas, ignora completamente os caracteres em minúsculas e transforma todos os outros caracteres em novas linhas. Claro, então você acaba com uma tonelada de linhas em branco. A
tr
-s
opção de repetição de queeze pode ser útil nesse caso, mas se você a usar ao lado da transformação[:upper:]
para, também acabará[:lower:]
apertando caracteres maiúsculos. Dessa forma, ainda requer um segundo filtro como ......ou...
... e acaba sendo muito menos conveniente do que fazer ...
... que comprime o
-c
omplement de caracteres alfabéticos por sequência em uma única nova linha de uma peça e depois faz a transformação de cima para baixo no outro lado do pipe.Isso não quer dizer que faixas dessa natureza não sejam úteis. Coisas como:
... pode ser bastante útil, pois converte os bytes de entrada em todos os dígitos em um espectro de dispersão de seus valores. Não desperdice, não queira, você sabe.
Outra maneira de fazer a transformação pode envolver
dd
.Como
dd
pode fazer as duas coisasunblock
e aslcase
conversões ao mesmo tempo, pode até ser possível passar muito do trabalho para ele. Mas isso só pode ser realmente útil se você puder prever com precisão o número de bytes por palavra - ou pelo menos conseguir preencher cada palavra com espaços de antemão para uma contagem previsível de bytes, porqueunblock
come espaços à direita no final de cada bloco.fonte
dd
envolvido :)