Estou fazendo algo em que percebi que queria contar quantos /
s eu conseguia encontrar em uma sequência, e então me ocorreu que havia várias maneiras de fazer isso, mas não conseguia decidir qual era o melhor (ou mais fácil) .
No momento eu vou com algo como:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
Mas eu não gosto de nada, todos os compradores?
Eu realmente não quero cavar RegEx
para isso, não é?
Eu sei que minha string terá o termo que estou procurando, então você pode assumir que ...
Claro que para strings em que length> 1 ,
string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;
LEN(ColumnToCheck) - LEN(REPLACE(ColumnToCheck,"N",""))
.Respostas:
Se você estiver usando o .NET 3.5, poderá fazer isso em uma linha com o LINQ:
Se você não quiser usar o LINQ, poderá fazê-lo com:
Você pode se surpreender ao saber que sua técnica original parece ser cerca de 30% mais rápida que qualquer uma delas! Acabei de fazer uma referência rápida com "/ once / upon / a / time /" e os resultados são os seguintes:
(Os horários são de 50.000.000 de iterações, portanto é improvável que você note muita diferença no mundo real.)
fonte
f == '\'
é de cerca de caracteres em uma string, não strings em uma stringTem que ser mais rápido que o
source.Replace()
próprio.fonte
fonte
RegexOptions.IgnoreCase
.Regex.Escape(...)
assimnew System.Text.RegularExpressions.Regex(needle).Matches(haystack).Count;
Se você deseja pesquisar cadeias inteiras, e não apenas caracteres:
Leia como "para cada caractere da string, pegue o restante da string a partir desse caractere como uma substring; conte-a se ela começar com a string de destino".
fonte
Fiz algumas pesquisas e descobri que a solução de Richard Watson é mais rápida na maioria dos casos. Essa é a tabela com os resultados de todas as soluções da postagem (exceto aqueles que usam Regex porque lança exceções ao analisar a string como "test {test")
Você pode ver que, no caso de encontrar o número de ocorrências de substrings curtos (1 a 5 caracteres) na cadeia curta (10 a 50 caracteres), o algoritmo original é o preferido.
Além disso, para substring de vários caracteres, você deve usar o seguinte código (com base na solução de Richard Watson )
fonte
Regex.Escape(needle)
source="aaa" substring="aa"
que eu esperava para voltar 2, não 1. Para "corrigir" isto, a mudançan += substring.Length
paran++
overlapped
bandeira para atender seu caso da seguinte maneira:overlapped=True;.... if(overlapped) {++n;} else {n += substring.Length;}
O LINQ funciona em todas as coleções e, como as seqüências de caracteres são apenas uma coleção de caracteres, que tal esse pequeno e simples comentário:
Verifique se você tem
using System.Linq;
na parte superior do seu arquivo de código, como.Count
é um método de extensão desse espaço para nome.fonte
int
todas as letras residem nas chaves domésticas, enquantovar
não. uh .. espera, eu estou usando DvorakNo meu computador, é cerca de 2 segundos mais rápido que a solução para todos os caracteres, para 50 milhões de iterações.
Revisão de 2013:
Mude a string para um char [] e repita isso. Corta mais um ou dois segundos no tempo total para iterações de 50m!
Isso é mais rápido ainda:
Para uma boa medida, a iteração do final da matriz para 0 parece ser a mais rápida, em cerca de 5%.
Fiquei me perguntando por que isso poderia ser e estava pesquisando no Google (lembro-me de algo sobre a iteração reversa ser mais rápida), e me deparei com essa pergunta do SO, que irritantemente usa a string para char [] já. Eu acho que o truque de reversão é novo neste contexto, no entanto.
Qual é a maneira mais rápida de iterar caracteres individuais em uma string em C #?
fonte
source.IndexOf('/', n + 1)
e perder osn++
colchetes do tempo :) Além disso, coloque uma variável emstring word = "/"
vez do caractere.fonte
Ambos funcionam apenas para termos de pesquisa de um caractere ...
pode vir a ser melhor para agulhas mais longas ...
Mas tem que haver uma maneira mais elegante. :)
fonte
Editar:
fonte
source.Split(new[]{"//"}, StringSplitOptions.None).Count - 1
para separadores de vários caracteres.Em C #, um bom contador String SubString é esse sujeito inesperadamente complicado:
fonte
fonte
stringToMatch
necessidades escapam, não asinput
.Como a solução original foi a mais rápida para caracteres, acho que também será para seqüências de caracteres. Então aqui está minha contribuição.
Para o contexto: eu estava procurando palavras como 'falhou' e 'conseguiu' em um arquivo de log.
Gr, Ben
fonte
fonte
Para quem deseja um método de extensão String pronto para usar,
Aqui está o que eu uso, baseado nas melhores respostas postadas:
fonte
fonte
Eu acho que a maneira mais fácil de fazer isso é usar as expressões regulares. Dessa forma, você pode obter a mesma contagem de divisão que poderia usando myVar.Split ('x'), mas em uma configuração de vários caracteres.
fonte
Isso será contado sempre que o programa encontrar "/ s" exatamente (diferencia maiúsculas de minúsculas) e o número de ocorrências disso será armazenado na variável "ocorrências"
fonte
Senti que estavam faltando certos tipos de contagem de sub-strings, como comparações inseguras de byte a byte. Eu montei o método do pôster original e todos os métodos que consegui pensar.
Estas são as extensões de string que eu fiz.
Seguido pelo código de teste ...
Resultados: o CSX corresponde ao CountSubstrX e o CCX corresponde ao CountCharX. "chr" pesquisa uma string por '_', "e" pesquisa uma string por "e", e "mlw" pesquisa uma string por "muchlongerword"
E, finalmente, eu tinha um arquivo com 3,6 milhões de caracteres. Foi "derp adfderdserp dfaerpderp deasderp" repetido 100.000 vezes. Eu procurei por "derp" dentro do arquivo com os métodos acima 100 vezes esses resultados.
Portanto, meu quarto método é definitivamente o vencedor, mas, realisticamente, se um arquivo de 3,6 milhões de caracteres 100 vezes levar apenas 1586ms como o pior caso, tudo isso será desprezível.
A propósito, também procurei o 'd' char no arquivo de 3,6 milhões de caracteres com 100 vezes os métodos CountSubstr e CountChar. Resultados...
O método original de pôsteres é muito ruim para agulhas de caractere único em um palheiro grande, de acordo com isso.
Nota: Todos os valores foram atualizados para a saída da versão Release. Esqueci-me acidentalmente de usar o modo Release na primeira vez que publiquei isso. Algumas das minhas declarações foram alteradas.
fonte
Uma função genérica para ocorrências de strings:
fonte
Uma variação na resposta de Richard Watson, um pouco mais rápida com a melhoria da eficiência quanto mais vezes o caractere ocorre na string e menos código!
Embora eu deva dizer, sem testar extensivamente todos os cenários, vi uma melhoria de velocidade muito significativa usando:
fonte
Precisava fazer algo semelhante para testar instruções condicionais de uma string.
Substituiu o que eu estava procurando por um único caractere e contou as instâncias do único caractere.
Obviamente, o único caractere que você está usando precisará ser verificado para não existir na string antes que isso aconteça para evitar contagens incorretas.
fonte
String em string:
Encontre "etc" em ".. JD JD JD JD etc. e etc. JDJDJDJDJDJDJDJD e etc."
Verifique o desempenho antes de descartar este como doentio / desajeitado ...
fonte
Minha visão inicial me deu algo como:
A agulha em uma abordagem de palheiro usando substituição e divisão produz 21+ segundos, enquanto isso leva cerca de 15,2.
Edite depois de adicionar um pouco que adicionaria
substring.Length - 1
ao charIndex (como deveria), em 11,6 segundos.Edit 2: usei uma string que tinha 26 strings de dois caracteres, aqui estão os horários atualizados para os mesmos textos de exemplo:
Agulha no palheiro (versão do OP): 7.8 Segundos
Mecanismo sugerido: 4,6 segundos.
Edit 3: Adicionando a caixa de canto de um caractere, foi para 1,2 segundos.
Editar 4: Para o contexto: 50 milhões de iterações foram usadas.
fonte
Pensei em jogar meu método de extensão no ringue (veja os comentários para mais informações). Não fiz nenhuma marcação formal de banco, mas acho que deve ser muito rápido para a maioria dos cenários.
EDIT: OK - então essa pergunta SO me levou a pensar em como o desempenho da nossa implementação atual se compara a algumas das soluções apresentadas aqui. Decidi fazer uma pequena marcação de banco e descobri que nossa solução estava muito alinhada com o desempenho da solução fornecida por Richard Watson até você fazer uma pesquisa agressiva com grandes seqüências de caracteres (100 Kb +), substrings grandes (32 Kb + ) e muitas repetições incorporadas (10K +). Nesse ponto, nossa solução era 2X a 4X mais lenta. Dado isso e o fato de realmente gostarmos da solução apresentada por Richard Watson, refatoramos nossa solução de acordo. Eu só queria disponibilizar isso para qualquer um que pudesse se beneficiar.
Nossa solução original:
E aqui está a nossa solução revisada:
fonte
fonte
Ele apenas verifica todos os caracteres da string. Se o caractere é o que você está procurando, adicione um para contar.
fonte
Se você verificar esta página da Web , serão comparadas 15 maneiras diferentes de fazer isso, incluindo o uso de loops paralelos.
A maneira mais rápida parece estar usando um loop for de thread único (se você tiver .Net versão <4.0) ou um loop parallel.for (se estiver usando .Net> 4.0 com milhares de verificações).
Supondo que "ss" seja sua String de Pesquisa, "ch" seja sua matriz de caracteres (se você tiver mais de um caractere que está procurando), aqui está a essência básica do código que teve o tempo de execução mais rápido único:
O código-fonte de referência também é fornecido para que você possa executar seus próprios testes.
fonte
Isto é para contar a ocorrência do personagem. Neste exemplo, a saída será "a4b4j3"
fonte
Para o caso de um delimitador de string (não para o caso char, como o sujeito diz):
string source = "@@@ uma vez @@@ em @@@ a @@@ time @@@";
int count = source.Split (novo [] {"@@@"}, StringSplitOptions.RemoveEmptyEntries) .Length - 1;
O delimitador natural do valor-fonte original do pôster ("/ once / upon / a / time /") é um caractere '/' e as respostas explicam a opção source.Split (char []) ...
fonte
using System.Linq;
int CountOf => "A :: BC :: D" .Split ("::"). Length - 1;
fonte