Qual é a maneira mais rápida de contar o número de cada caractere em um arquivo?


121

Eu quero contar os caracteres N's e "-" de A's T's C's e "-" em um arquivo, ou todas as letras, se necessário, existe um comando rápido do Unix para fazer isso?


56
Contando bases em filamentos de DNA?
Indrek 10/10

12
Eu amo essa pergunta, tantas abordagens e ferramentas diferentes usadas para resolver o mesmo problema.
Journeyman Geek

10
Heh, este é limítrofe código-golf
Earlz

13
se alguém estiver interessado na versão do Windows PowerShell:[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Guillaume86

4
Ok, acho que encontrei o caminho do PS puro:Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Guillaume86

Respostas:


136

Se você quer um pouco de velocidade real:

echo 'int cache[256],x,y;char buf[4096],letters[]="tacgn-"; int main(){while((x=read(0,buf,sizeof buf))>0)for(y=0;y<x;y++)cache[(unsigned char)buf[y]]++;for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -w -xc -; ./a.out < file; rm a.out;

É um pseudo-one-liner incrivelmente rápido.

Um teste simples mostra que, na minha CPU Core i7 870 a 2.93GHz, conta com pouco mais de 600MB / s:

$ du -h bigdna 
1.1G    bigdna

time ./a.out < bigdna 
t: 178977308
a: 178958411
c: 178958823
g: 178947772
n: 178959673
-: 178939837

real    0m1.718s
user    0m1.539s
sys     0m0.171s

Diferentemente das soluções que envolvem classificação, esta é executada na memória constante (4K), o que é muito útil se o seu arquivo for muito maior que o seu ram.

E, é claro, com um pouco de graxa nos cotovelos, podemos cortar 0,7 segundos:

echo 'int cache[256],x,buf[4096],*bp,*ep;char letters[]="tacgn-"; int main(){while((ep=buf+(read(0,buf,sizeof buf)/sizeof(int)))>buf)for(bp=buf;bp<ep;bp++){cache[(*bp)&0xff]++;cache[(*bp>>8)&0xff]++;cache[(*bp>>16)&0xff]++;cache[(*bp>>24)&0xff]++;}for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -O2 -xc -; ./a.out < file; rm a.out;

Redes com pouco mais de 1,1 GB / s de acabamento em:

real    0m0.943s
user    0m0.798s
sys     0m0.134s

Para comparação, testei algumas das outras soluções nesta página que pareciam ter algum tipo de promessa de velocidade.

A solução sed/ awkfez um grande esforço, mas morreu após 30 segundos. Com um regex tão simples, espero que seja um bug no sed (GNU sed versão 4.2.1):

$ time sed 's/./&\n/g' bigdna | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}' 
sed: couldn't re-allocate memory

real    0m31.326s
user    0m21.696s
sys     0m2.111s

O método perl parecia promissor também, mas desisti depois de executá-lo por 7 minutos

time perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c' < bigdna 
^C

real    7m44.161s
user    4m53.941s
sys     2m35.593s

1
+1 Para uma solução sã quando há muitos dados, e não apenas um punhado de bytes. Os arquivos estão no cache do disco, não estão?
Daniel Beck

2
O interessante é que ele tem uma complexidade de O (N) no processamento e O (1) na memória. Os tubos geralmente têm O (N log N) em processamento (ou mesmo O (N ^ 2)) e O (N) na memória.
Martin Ueding 10/10/12

73
Você está ampliando bastante a definição de "linha de comando".
gerrit

11
Curvatura épica dos requisitos da pergunta - eu aprovo; p. superuser.com/a/486037/10165 <- alguém executou benchmarks, e esta é a opção mais rápida.
Journeyman Geek

2
+1 Aprecio-me um bom uso de C nos lugares certos.
11134 Jeff Ferland

119

grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

Vai fazer o truque como um forro. Uma pequena explicação é necessária.

grep -o foo.text -e A -e T -e C -e G -e N -e -recebe o arquivo foo.text pelas letras aeg e o caractere -para cada caractere que você deseja procurar. Também imprime um caractere por linha.

sortclassifica em ordem. Isso prepara o cenário para a próxima ferramenta

uniq -cconta as ocorrências consecutivas duplicadas de qualquer linha. Nesse caso, como temos uma lista classificada de caracteres, obtemos uma contagem clara de quando os caracteres que saímos na primeira etapa

Se foo.txt contivesse a string, GATTACA-é isso que eu obteria deste conjunto de comandos

[geek@atremis ~]$ grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
      1 -
      3 A
      1 C
      1 G
      2 T

8
Sangrenta magia unix! : D
Pitto 10/10/12

27
se houver apenas caracteres CTAG em seus arquivos, o próprio regexp se tornará inútil, certo? grep -o. | classificar | O uniq -c funcionaria igualmente bem, apesar de tudo.
sylvainulg

7
+1 Uso o grep há 25 anos e não sabia -o.
LarsH 10/10

9
@JourneymanGeek: O problema disso é que ele gera muitos dados que são encaminhados para classificação. Seria mais barato deixar um programa analisar cada caractere. Consulte a resposta de Dave para obter uma resposta de complexidade de memória O (1) em vez de O (N).
Martin Ueding 10/10/12

2
@Pitto nativo do Windows constrói de coreutils estão amplamente disponíveis - basta perguntar Google ou algo assim
OrangeDog

46

Experimente este, inspirado na resposta de @ Journeyman.

grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c

A chave é conhecer a opção -o para grep . Isso divide a correspondência, para que cada linha de saída corresponda a uma única instância do padrão, em vez da linha inteira para qualquer linha que corresponda. Dado esse conhecimento, tudo o que precisamos é de um padrão a ser usado e uma maneira de contar as linhas. Usando uma regex, podemos criar um padrão disjuntivo que corresponderá a qualquer um dos caracteres mencionados:

A|T|C|G|N|-

Isso significa "combinar A ou T ou C ou G ou N ou -". O manual descreve várias sintaxes de expressão regular que você pode usar .

Agora temos uma saída parecida com esta:

$ grep -o -E 'A|T|C|G|N|-' foo.txt 
A
T
C
G
N
-
-
A
A
N
N
N

Nosso último passo é mesclar e contar todas as linhas semelhantes, que podem ser simplesmente realizadas com a sort | uniq -c, como na resposta de @ Journeyman. A classificação nos dá uma saída como esta:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort
-
-
A
A
A
C
G
N
N
N
N
T

Que, quando transmitido uniq -c, finalmente se assemelha ao que queremos:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c
      2 -
      3 A
      1 C
      1 G
      4 N
      1 T

Adendo: Se você quiser totalizar o número de caracteres A, C, G, N, T e - em um arquivo, poderá canalizar a saída grep em wc -lvez de sort | uniq -c. Há muitas coisas diferentes que você pode contar com apenas pequenas modificações nessa abordagem.


Eu realmente preciso me aprofundar nos coelhos que são coreutils e regex. Isso é um pouco mais elegante do que o meu; p
Journeyman Geek

2
@JourneymanGeek: aprender regex vale bem a pena, pois é útil para muitas coisas. Apenas entenda as limitações e não abuse do poder, tentando fazer coisas fora do escopo dos recursos de expressões regulares, como tentar analisar XHTML .
221312 crazy2be

20
grep -o '[ATCGN-]' poderia ser um pouco mais legível aqui.
sylvainulg

14

Um liner contando todas as letras usando Python:

$ python -c "import collections, pprint; pprint.pprint(dict(collections.Counter(open('FILENAME_HERE', 'r').read())))"

... produzindo uma saída amigável para YAML como esta:

{'\n': 202,
 ' ': 2153,
 '!': 4,
 '"': 62,
 '#': 12,
 '%': 9,
 "'": 10,
 '(': 84,
 ')': 84,
 '*': 1,
 ',': 39,
 '-': 5,
 '.': 121,
 '/': 12,
 '0': 5,
 '1': 7,
 '2': 1,
 '3': 1,
 ':': 65,
 ';': 3,
 '<': 1,
 '=': 41,
 '>': 12,
 '@': 6,
 'A': 3,
 'B': 2,
 'C': 1,
 'D': 3,
 'E': 25}

É interessante ver como na maioria das vezes o Python pode facilmente superar o bash em termos de clareza de código.


11

Semelhante ao awkmétodo do Guru :

perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c'

10

Depois de usar o UNIX por alguns anos, você obtém muita habilidade em vincular várias operações pequenas para realizar várias tarefas de filtragem e contagem. Todo mundo tem sua própria style-- alguns gostam awke sed, alguns, como cute tr. Aqui está a maneira que eu faria:

Para processar um nome de arquivo específico:

 od -a FILENAME_HERE | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

ou como um filtro:

 od -a | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

Funciona assim:

  1. od -a separa o arquivo em caracteres ASCII.
  2. cut -b 9-elimina o prefixo de odvenda.
  3. tr " " \\n converte os espaços entre os caracteres em novas linhas, para que haja um caractere por linha.
  4. egrep -v "^$" se livra de todas as linhas em branco extras que isso cria.
  5. sort reúne instâncias de cada personagem juntos.
  6. uniq -c conta o número de repetições de cada linha.

Eu alimentei "Olá, mundo!" seguido por uma nova linha e conseguiu o seguinte:

  1 ,
  1 !
  1 d
  1 e
  1 H
  3 l
  1 nl
  2 o
  1 r
  1 sp
  1 w

9

Com a sedparte baseada na resposta do @ Guru , aqui está outra abordagem uniq, semelhante à solução de David Schwartz.

$ cat foo
aix
linux
bsd
foo
$ sed 's/\(.\)/\1\n/g' foo | sort | uniq -c
4 
1 a
1 b
1 d
1 f
2 i
1 l
1 n
2 o
1 s
1 u
2 x

1
Use [[:alpha:]]em vez de .em sedapenas aos personagens de jogo e não novas linhas.
Cláudio

1
[[:alpha:]]falhará se você também está tentando combinar coisas assim -, que foi mencionado na pergunta
Izkata

Corrigir. Pode ser mais agradável para adicionar uma segunda expressão de sed a primeira filtrar tudo e, em seguida, corresponder explicitamente os caracteres desejados: sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c. No entanto, não sei como me livrar das novas linhas lá: \
Claudius

7

Você pode combinar grepe wcfazer isso:

grep -o 'character' file.txt | wc -w

greppesquisa o (s) arquivo (s) fornecido (s) pelo texto especificado e a -oopção solicita que ele imprima apenas as correspondências reais (ou seja, os caracteres que você estava procurando), em vez do padrão que é imprimir cada linha na qual o texto de pesquisa foi encontrado em.

wcimprime as contagens de bytes, palavras e linhas de cada arquivo ou, nesse caso, a saída do grepcomando. A -wopção diz para contar palavras, com cada palavra sendo uma ocorrência do seu caractere de pesquisa. Obviamente, a -lopção (que conta as linhas) também funcionaria, pois grepimprime cada ocorrência do seu caractere de pesquisa em uma linha separada.

Para fazer isso para vários caracteres de uma vez, coloque os caracteres em uma matriz e faça um loop sobre ela:

chars=(A T C G N -)
for c in "${chars[@]}"; do echo -n $c ' ' && grep -o $c file.txt | wc -w; done

Exemplo: para um arquivo contendo a sequência TGC-GTCCNATGCGNNTCACANN-, a saída seria:

A  3
T  4
C  6
G  4
N  5
-  2

Para mais informações, consulte man grepe man wc.


A desvantagem dessa abordagem, como o usuário Journeyman Geek observa abaixo em um comentário, é que grepdeve ser executada uma vez para cada personagem. Dependendo do tamanho dos seus arquivos, isso pode resultar em um impacto perceptível no desempenho. Por outro lado, quando feito dessa maneira, é um pouco mais fácil ver rapidamente quais caracteres estão sendo pesquisados ​​e adicioná-los / removê-los, pois eles estão em uma linha separada do restante do código.


3
eles precisariam repeti-lo por personagem que desejarem ... eu acrescentaria. Eu poderia jurar que não há uma solução mais elegante, mas ele precisa de mais picar; p
Journeyman Geek

@JourneymanGeek Good point. Uma abordagem que vem à mente é colocar os caracteres em uma matriz e percorrê-la. Eu atualizei minha postagem.
Indrek 10/10

IMO muito complexo. Basta usar grep -ea -et e assim por diante. Se você colocá-lo em uma matriz e percorrê-lo, não precisaria executar o ciclo grep uma vez por caractere?
Journeyman Geek

@JourneymanGeek Você provavelmente está certo. uniq -ctambém parece ser uma maneira melhor de obter uma saída bem formatada. Eu não sou nenhum guru * nix, o acima é apenas o que eu consegui colocar junto de meu conhecimento limitado e algumas páginas man :)
Indrek

Eu também; p, e uma das minhas atribuições no último período envolvia a classificação de cerca de 5000 entradas do catálogo de endereços, e o uniq tornou muito mais fácil.
Journeyman Geek

7

Usando as linhas de sequência de 22hgp10a.txt, a diferença de tempo entre grep e awk no meu sistema faz do awk o caminho a percorrer ...

[Editar]: Depois de ver a solução compilada de Dave, esqueça também o awk, pois ele foi concluído em ~ 0,1 segundos neste arquivo para uma contagem completa entre maiúsculas e minúsculas.

# A nice large sample file.
wget http://gutenberg.readingroo.ms/etext02/22hgp10a.txt

# Omit the regular text up to the start `>chr22` indicator.
sed -ie '1,/^>chr22/d' 22hgp10a.txt

sudo test # Just get sudo setup to not ask for password...

# ghostdog74 answered a question <linked below> about character frequency which
# gave me all case sensitive [ACGNTacgnt] counts in ~10 seconds.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
awk -vFS="" '{for(i=1;i<=NF;i++)w[$i]++}END{for(i in w) print i,w[i]}' 22hgp10a.txt

# The grep version given by Journeyman Geek took a whopping 3:41.47 minutes
# and yielded the case sensitive [ACGNT] counts.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

A versão sem diferenciação de maiúsculas e minúsculas do ghostdog é concluída em ~ 14 segundos.

O sed é explicado na resposta aceita a esta pergunta .
O benchmarking é como na resposta aceita a esta pergunta .
A resposta aceita por ghostdog74 foi para esta pergunta .


1
Você pode trabalhar s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]para torná-lo sem distinção entre maiúsculas e minúsculas sem afetar sua velocidade.
Dave

6

Eu acho que qualquer implementação decente evita classificação. Mas como também é uma má ideia ler tudo 4 vezes, acho que de alguma forma podemos gerar um fluxo que passa por 4 filtros, um para cada caractere, que é filtrado e onde os comprimentos do fluxo também são calculados de alguma forma.

time cat /dev/random | tr -d -C 'AGCTN\-' | head -c16M >dna.txt
real    0m5.797s
user    0m6.816s
sys     0m1.371s

$ time tr -d -C 'AGCTN\-' <dna.txt | tee >(wc -c >tmp0.txt) | tr -d 'A' | 
tee >(wc -c >tmp1.txt) | tr -d 'G' | tee >(wc -c >tmp2.txt) | tr -d 'C' | 
tee >(wc -c >tmp3.txt) | tr -d 'T' | tee >(wc -c >tmp4.txt) | tr -d 'N' | 
tee >(wc -c >tmp5.txt) | tr -d '\-' | wc -c >tmp6.txt && cat tmp[0-6].txt

real    0m0.742s
user    0m0.883s
sys     0m0.866s

16777216
13983005
11184107
8387205
5591177
2795114
0

As somas cumulativas estão então em tmp [0-6] .txt .. portanto, o trabalho ainda está em andamento

Existem apenas 13 canais nesta abordagem, que são convertidos em menos de 1 Mb de memória.
Claro que minha solução favorita é:

time cat >f.c && gcc -O6 f.c && ./a.out
# then type your favourite c-program
real    0m42.130s

Este é um uso muito agradável de tr.
adavid

4

Eu não sabia uniqnem sabia grep -o, mas como meus comentários em @JourneymanGeek e @ crazy2be tiveram esse apoio, talvez eu devesse transformá-lo em uma resposta própria:

Se você sabe que existem apenas caracteres "bons" (aqueles que você deseja contar) em seu arquivo, você pode procurar

grep . -o YourFile | sort | uniq -c

Se apenas alguns caracteres devem ser contados e outros não (ou seja, separadores)

grep '[ACTGN-]' YourFile | sort | uniq -c

O primeiro usa o curinga da expressão regular ., que corresponde a qualquer caractere único. O segundo usa um 'conjunto de caracteres aceitos', sem ordem específica, exceto que -deve vir por último ( A-Cé interpretado como 'qualquer caractere entre Ae C). As cotações são necessárias nesse caso, para que seu shell não tente expandi-lo para verificar arquivos de um caractere, se houver (e produzir um erro "sem correspondência", se não houver).

Observe que "sort" também possui um -usinalizador nique, para que ele relate apenas as coisas uma vez, mas nenhum sinal complementar para contar duplicatas, portanto uniqé obrigatório.


-não precisa vir por último se você escapar com uma barra invertida: '[A\-CTGN]'deve funcionar muito bem.
Indrek 11/11

2

Um tolo:

tr -cd ATCGN- | iconv -f ascii -t ucs2 | tr '\0' '\n' | sort | uniq -c
  • trpara excluir ( -d) todos os caracteres, mas ( -c) ATCGN-
  • iconv converter em ucs2 (UTF16 limitado a 2 bytes) para adicionar um byte 0 após cada byte,
  • outro trpara traduzir esses caracteres NUL para NL. Agora cada personagem está na sua própria linha
  • sort | uniq -ccontar cada linha uniq

Essa é uma alternativa à -oopção grep não padrão (GNU) .


Você poderia dar uma breve explicação dos comandos e da lógica aqui?
Andrew Lambert

2
time $( { tr -cd ACGTD- < dna.txt | dd | tr -d A | dd | tr -d C | dd | tr -d G |
dd | tr -d T | dd | tr -d D | dd | tr -d - | dd >/dev/null; } 2>tmp ) &&
grep byte < tmp | sort -r -g | awk '{ if ((s-$0)>=0) { print s-$0} s=$0 }'

O formato de saída não é o melhor ...

real    0m0.176s
user    0m0.200s
sys     0m0.160s
2069046
2070218
2061086
2057418
2070062
2052266

Teoria de Operação:

  • $ ({command | command} 2> tmp) redireciona o stderr do fluxo para um arquivo temporário.
  • dd gera stdin para stdout e gera o número de bytes passados ​​para stderr
  • tr -d filtra um caractere de cada vez
  • grep and sort filtra a saída de dd em ordem decrescente
  • awk calcula a diferença
  • A classificação é usada apenas no estágio de pós-processamento para lidar com a incerteza da ordem de saída das instâncias de dd

A velocidade parece ser 60MBps +


Melhorias: livrar-se do tmp? usar 'colar' para imprimir a carta envolvida?
Aki Suihkonen 11/10/12

1

Arquivo de exemplo:

$ cat file
aix
unix
linux

Comando:

$ sed 's/./&\n/g' file | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}'
u 2
i 3
x 3
l 1
n 2
a 1

-1 por falta de clareza e por postar uma linha sem explicação. AFAIK, isso poderia ser uma bomba de forquilha
PPC

1

Combinando alguns outros

chars='abcdefghijklmnopqrstuvwxyz-'
grep -o -i "[$chars]" foo|sort | uniq -c

Adicione | sort -nrpara ver os resultados em ordem de frequência.


1

Resposta curta:

Se as circunstâncias permitirem, compare os tamanhos de arquivo de conjuntos de caracteres baixos com um sem caracteres para obter um deslocamento e apenas contar bytes.

Ah, mas os detalhes emaranhados:

Esses são todos os personagens Ascii. Um byte por. É claro que os arquivos têm metadados extras anexados a uma variedade de coisas usadas pelo sistema operacional e pelo aplicativo que os criou. Na maioria dos casos, eu esperaria que eles ocupassem a mesma quantidade de espaço, independentemente dos metadados, mas tentaria manter circunstâncias idênticas ao testar a abordagem pela primeira vez e, em seguida, verificar se você tem um deslocamento constante antes de não se preocupar com isso. A outra dica é que as quebras de linha geralmente envolvem dois caracteres de espaço em branco ascii e qualquer guia ou espaço seria um cada. Se você tiver certeza de que eles estarão presentes e não há como saber quantos de antemão, eu pararia de ler agora.

Pode parecer um monte de restrições, mas se você pode defini-las facilmente, isso me parece a abordagem mais fácil / com melhor desempenho se você tiver uma tonelada delas para analisar (o que parece provável se for DNA). Verificar uma tonelada de arquivos quanto ao comprimento e subtrair uma constante seria mais rápido do que executar o grep (ou similar) em cada um.

E se:

  • Essas são seqüências simples e ininterruptas em arquivos de texto puro
  • Eles estão em tipos de arquivos idênticos, criados pelo mesmo editor de texto sem formatação de baunilha, como o Scite (colar é bom, desde que você verifique espaços / retornos) ou algum programa básico que alguém escreveu

E duas coisas que talvez não importem, mas eu testaria primeiro

  • Os nomes dos arquivos têm o mesmo comprimento
  • Os arquivos estão no mesmo diretório

Tente encontrar o deslocamento, fazendo o seguinte:

Compare um arquivo vazio com um com alguns caracteres facilmente contáveis ​​por humanos com um com mais alguns caracteres. Se subtrair o arquivo vazio dos dois outros arquivos fornecer contagens de bytes correspondentes à contagem de caracteres, você estará pronto. Verifique os comprimentos dos arquivos e subtraia esse valor vazio. Se você quiser descobrir arquivos com várias linhas, a maioria dos editores anexa dois caracteres especiais de um byte para quebras de linha, uma vez que um tende a ser ignorado pela Microsoft, mas você deve pelo menos esperar por caracteres de espaço em branco. você pode fazer tudo com grep.


1

Maneira de Haskell :

import Data.Ord
import Data.List
import Control.Arrow

main :: IO ()
main = interact $
  show . sortBy (comparing fst) . map (length &&& head) . group . sort

funciona assim:

112123123412345
=> sort
111112222333445
=> group
11111 2222 333 44 5
=> map (length &&& head)
(5 '1') (4 '2') (3 '3') (2 '4') (1,'5')
=> sortBy (comparing fst)
(1 '5') (2 '4') (3 '3') (4 '2') (5 '1')
=> one can add some pretty-printing here
...

compilando e usando:

$ ghc -O2 q.hs
[1 of 1] Compiling Main             ( q.hs, q.o )
Linking q ...
$ echo 112123123412345 | ./q
[(1,'\n'),(1,'5'),(2,'4'),(3,'3'),(4,'2'),(5,'1')]%       
$ cat path/to/file | ./q
...

talvez não seja bom para arquivos grandes.


1

Quick perl hack:

perl -nle 'while(/[ATCGN]/g){$a{$&}+=1};END{for(keys(%a)){print "$_:$a{$_}"}}'
  • -n: Itere sobre as linhas de entrada, mas não imprima nada para elas
  • -l: Tira ou adiciona quebras de linha automaticamente
  • while: repete todas as ocorrências dos símbolos solicitados na linha atual
  • END: No final, imprima os resultados
  • %a: Hash onde os valores são armazenados

Caracteres que não ocorrem de todo não serão incluídos no resultado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.