Eu queria saber como contar o número de um caractere específico em cada linha por alguns utilitários de processamento de texto?
Por exemplo, para contar "
em cada linha do texto a seguir
"hello!"
Thank you!
A primeira linha tem dois e a segunda linha tem 0.
Outro exemplo é contar (
em cada linha.
text-processing
Tim
fonte
fonte
Respostas:
Você pode fazer isso com
sed
eawk
:Onde
dat
está o texto de exemplo, sed exclui (para cada linha) todos os não"
caracteres eawk
imprime para cada linha seu tamanho (ou seja,length
é equivalente alength($0)
, onde$0
denota a linha atual).Para outro personagem, você apenas precisa alterar a expressão sed. Por exemplo, para
(
:Atualização:
sed
é um exagero para a tarefa -tr
é suficiente. Uma solução equivalente comtr
é:Significa que
tr
exclui todos os caracteres que não estão (-c
significa complemento) no conjunto de caracteres"\n
.fonte
tr
&wc
.ß
(utf hex: c3 9f) (em vez de"
) funciona conforme o esperado, ou sejatr
,sed
eawk
complementa / substitui / conta sem problemas - em um sistema Ubuntu 10.04.tr
, incluindo GNU tr e clássico Unix tr, opera com caracteres de byte único e não é compatível com Unicode. Citado em Wikipedia tr (Unix) . Experimente este trecho:echo "aā⧾c" | tr "ā⧾" b
... no Ubuntu 10.04 ...ß
é um byte único Caractere latino estendido e é tratado portr
... O verdadeiro problema aqui não é quetr
não lida com Unicode (porque TODOS os caracteres são Unicode), é realmente quetr
lida apenas com um byte de cada vez ..Eu usaria apenas awk
Aqui, definimos o separador de campos (com o sinalizador -F) como o caractere;
"
tudo o que fazemos é imprimir o número de camposNF
- 1. O número de ocorrências do caractere de destino será um a menos que o número de campos separados.Para personagens engraçados que são interpretados pelo shell, você só precisa escapar deles, caso contrário a linha de comando tentará interpretá-los. Portanto, para ambos
"
e)
você precisa escapar do separador de campos (com\
).fonte
'
). Além disso, ele tem um comportamento estranho com linhas vazias."
então me sinto obrigado a fazer o código funcionar com ele. Depende do que desembolsar você estiver usando o tempo o personagem precisa ser escapado, mas bash / tcsh vai tanto precisa escapar "-F'"'
.awk -F"$1" '{print NF==0?NF:NF-1}' filename
Usando
tr
ardwc
:Uso:
fonte
tr
não lida com caracteres que usam mais de um byte. veja Wikipedia tr (Unix) .tr
não é compatível com Unicode.$IFS
, caso contrário,read
irá apará-los do início e do fim.echo
para dados arbitráriostr
implementações suportam caracteres multibyte, maswc -c
contam bytes, e não caracteres de qualquer maneira (necessidadewc -m
de caracteres).No entanto, outra aplicação que não depende de programas externos, em
bash
,zsh
,yash
e algumas implementações / versões deksh
:Use
line="${line//[!(]}"
para contar(
.fonte
eof=false; IFS=; until $eof; do read -r || eof=true; echo "$REPLY"; done
/
que não é necessária no bash. É um requisito ksh?/
é necessário nas versões mais antigas do ksh e no IIRC nas versões mais antigas do bash.As respostas que usam
awk
falham se o número de correspondências for muito grande (que é a minha situação). Para a resposta de loki-astari , o seguinte erro é relatado:Para a resposta do enzotib (e o equivalente do manatwork ), ocorre uma falha de segmentação:
A
sed
solução de maxschlepzig funciona corretamente, mas é lenta (intervalos abaixo).Algumas soluções ainda não sugeridas aqui. Primeiro, usando
grep
:E usando
perl
:Aqui estão alguns horários para algumas das soluções (ordenadas do mais lento para o mais rápido); Limitei as coisas a one-liners aqui. 'foo.txt' é um arquivo com uma linha e uma sequência longa que contém 84922 correspondências.
fonte
Outra
awk
solução:fonte
Outra implementação possível com o awk e o gsub:
A função
gsub
é equivalente a sed's's///g'
.Use
gsub("[^(]", "")
para contar(
.fonte
awk '{print gsub(/"/,"")}' input-file
seria suficiente, como "Para cada substring que corresponda à expressão regular r na string t, substitua a string s e retorne o número de substituições". (man awk)Decidi escrever um programa em C porque estava entediado.
Você provavelmente deve adicionar validação de entrada, mas fora isso está tudo pronto.
fonte
free(line)
porque o fato de sair do programa libera implicitamente toda a memória alocada - então há lugar para umreturn 0;
...;). Mesmo em exemplos, não é bom estilo deixar o código de retorno indefinido. Aliás,getline
é uma extensão GNU - caso alguém esteja se perguntando.f
, que é chamada várias vezes de outro código, será necessário chamarfree
após a última chamadagetline
no final desta funçãof
.Para uma string, o mais simples seria com
tr
ewc
(não é necessário exagerar comawk
oused
) - mas observe os comentários acima sobretr
, conta bytes, não caracteres -onde
$x
é a variável que contém a sequência (não um arquivo) a ser avaliada.fonte
Aqui está outra solução C que precisa apenas de STD C e menos memória:
fonte
\n
não é uma linha real. Esse é o mesmo comportamento da minha outra resposta sed / awk (tr / awk).Podemos usar
grep
comregex
para torná-lo mais simples e poderoso.Contar caracteres específicos.
Para contar caracteres especiais, incluindo caracteres de espaço em branco.
Aqui, estamos selecionando qualquer caractere com
[\S\s]
e com a-o
opção que fazemosgrep
para imprimir cada correspondência (ou seja, cada caractere) em uma linha separada. E então usewc -l
para contar cada linha.fonte
"
estão em cada linha; e para quaisquer outros caracteres. veja sua pergunta e também aceite a resposta.Talvez uma resposta mais direta e puramente estranha seria usar split. Split pega uma string e a transforma em uma matriz, o valor de retorno é o número de itens da matriz gerados + 1.
O código a seguir imprimirá o número de vezes "aparece em cada linha.
mais informações sobre http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html
fonte
Aqui está um script Python simples para encontrar a contagem de
"
em cada linha de um arquivo:Aqui nós usamos o
count
método dostr
tipo interno.fonte
Para uma solução de bash pura (no entanto, é específica do bash): If
$x
é a variável que contém sua string:A
${x//
coisa remove todos os caracteres"
, exceto ,${#x2}
calcula a duração desse descanso.(Sugestão original usando
expr
problemas, consulte os comentários:)fonte
expr
e conta bytes, não caracteres. Com outrosexpr
:expr "x${x...}" : "x.*" - 1
Substitua
a
pelo caractere a ser contado. Saída é o contador para cada linha.fonte
Comparação temporal das soluções apresentadas (não uma resposta)
A eficiência das respostas não é importante. No entanto, seguindo a abordagem @josephwb, tentei cronometrar todas as respostas apresentadas.
Utilizo como entrada a tradução em português de Victor Hugo "Les Miserables" (ótimo livro!) E conto as ocorrências de "a". Minha edição tem 5 volumes, muitas páginas ...
As respostas em C foram compiladas com o gcc (sem otimizações).
Cada resposta foi executada 3 vezes e escolha a melhor.
Não confie demais nesses números (minha máquina está realizando outras tarefas, etc.). Partilho esses momentos com você, porque obtive resultados inesperados e tenho certeza de que encontrará mais ...
grep -oP a
é o tempo da árvore mais rápido quegrep -o a
(10; 11 vs 12)(resulta em uma ordem aleatória)
fonte
onde grep faz todo o trabalho pesado: relata cada caractere encontrado em cada número de linha. O resto é apenas para somar a contagem por linha e formatar a saída.
Remova o
-n
e obtenha a contagem para o arquivo inteiro.Contar um arquivo de texto de 1,5Meg em menos de 0,015 segundos parece rápido.
E funciona com caracteres (não bytes).
fonte
Uma solução para o bash. Nenhum programa externo é chamado (mais rápido para cadeias curtas).
Se o valor estiver em uma variável:
Isso imprimirá quantas
"
contém:fonte