Estoy haciendo algo en el que me di cuenta de que quería contar cuántos /
s podía encontrar en una cadena, y luego me di cuenta de que había varias formas de hacerlo, pero no podía decidir cuál era la mejor (o la más fácil). .
Por el momento voy con algo como:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
Pero no me gusta en absoluto, ¿algún tomador?
Realmente no quiero cavar RegEx
para esto, ¿verdad?
Sé que mi cadena tendrá el término que estoy buscando, por lo que puede suponer que ...
Por supuesto para cadenas donde longitud> 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",""))
.Respuestas:
Si está utilizando .NET 3.5, puede hacerlo en una sola línea con LINQ:
Si no desea usar LINQ, puede hacerlo con:
¡Te sorprenderá saber que tu técnica original parece ser aproximadamente un 30% más rápida que cualquiera de estas! Acabo de hacer un punto de referencia rápido con "/ once / upon / a / time /" y los resultados son los siguientes:
(Los tiempos son para 50,000,000 de iteraciones, por lo que es poco probable que note mucha diferencia en el mundo real).
fuente
f == '\'
se trata de caracteres en una cadena, no cadenas en una cadenaTiene que ser más rápido que el
source.Replace()
solo.fuente
fuente
RegexOptions.IgnoreCase
.Regex.Escape(...)
esonew System.Text.RegularExpressions.Regex(needle).Matches(haystack).Count;
Si desea poder buscar cadenas enteras, y no solo caracteres:
Lea como "para cada carácter de la cadena, tome el resto de la cadena a partir de ese carácter como una subcadena; cuéntelo si comienza con la cadena de destino".
fuente
Investigué un poco y descubrí que la solución de Richard Watson es la más rápida en la mayoría de los casos. Esa es la tabla con los resultados de cada solución en la publicación (excepto aquellos que usan Regex porque arroja excepciones al analizar cadenas como "test {test")
Puede ver que en caso de encontrar el número de ocurrencias de subcadenas cortas (1-5 caracteres) en una cadena corta (10-50 caracteres), se prefiere el algoritmo original.
Además, para la subcadena de varios caracteres, debe usar el siguiente código (basado en la solución de Richard Watson )
fuente
Regex.Escape(needle)
source="aaa" substring="aa"
esperaba volver 2, no 1. Para "arreglar" esto, cambien += substring.Length
an++
overlapped
bandera para cumplir con su caso de esta manera:overlapped=True;.... if(overlapped) {++n;} else {n += substring.Length;}
LINQ funciona en todas las colecciones, y dado que las cadenas son solo una colección de personajes, ¿qué tal este simpático y sencillo:
Asegúrese de tener
using System.Linq;
en la parte superior de su archivo de código, ya que.Count
es un método de extensión de ese espacio de nombres.fuente
int
todas las letras residen en las teclas de inicio, mientrasvar
que no. eh ... espera, estoy usando DvorakEn mi computadora es aproximadamente 2 segundos más rápido que la solución para cada personaje para 50 millones de iteraciones.
Revisión 2013:
Cambia la cadena a char [] e itera a través de eso. ¡Corta uno o dos segundos más del tiempo total para iteraciones de 50 m!
Esto es más rápido aún:
En buena medida, iterar desde el final de la matriz hasta 0 parece ser el más rápido, en aproximadamente un 5%.
Me preguntaba por qué esto podría ser y estaba buscando en Google (recuerdo algo acerca de que la iteración inversa es más rápida), y me encontré con esta pregunta SO que molestamente usa la técnica string a char []. Sin embargo, creo que el truco de la inversión es nuevo en este contexto.
¿Cuál es la forma más rápida de iterar a través de caracteres individuales en una cadena en C #?
fuente
source.IndexOf('/', n + 1)
y perder losn++
y los corchetes del while :) Además, coloca una variable enstring word = "/"
lugar del carácter.fuente
Ambos solo funcionan para términos de búsqueda de un solo carácter ...
puede resultar mejor para agujas más largas ...
Pero tiene que haber una forma más elegante. :)
fuente
Editar:
fuente
source.Split(new[]{"//"}, StringSplitOptions.None).Count - 1
para separadores de caracteres múltiples.En C #, un buen contador de String SubString es este tipo inesperadamente complicado:
fuente
fuente
stringToMatch
necesidades escapan, no lasinput
.Debido a que la solución original era la más rápida para los caracteres, supongo que también será para las cadenas. Así que aquí está mi contribución.
Para el contexto: estaba buscando palabras como 'fallido' y 'exitoso' en un archivo de registro.
Gr, Ben
fuente
fuente
Para cualquiera que quiera un método de extensión String listo para usar,
Esto es lo que uso, que se basó en la mejor de las respuestas publicadas:
fuente
fuente
Creo que la forma más fácil de hacer esto es usar las expresiones regulares. De esta forma, puede obtener el mismo recuento dividido que podría usar myVar.Split ('x') pero en una configuración de múltiples caracteres.
fuente
Esto contará cada vez que el programa encuentre "/ s" exactamente (distingue entre mayúsculas y minúsculas) y el número de ocurrencias de esto se almacenará en la variable "ocurrencias"
fuente
Sentí que nos faltaban ciertos tipos de recuento de subcadenas, como comparaciones inseguras byte por byte. Reuní el método del póster original y cualquier método que se me ocurriera.
Estas son las extensiones de cadena que hice.
Seguido por el código de prueba ...
Resultados: CSX se corresponde con CountSubstrX y CCX se corresponde con CountCharX. "chr" busca una cadena para '_', "y" busca una cadena para "y", y "mlw" busca una cadena para "muchlongerword"
Y finalmente, tenía un archivo con 3.6 millones de caracteres. Fue "derp adfderdserp dfaerpderp deasderp" repetido 100.000 veces. Busqué "derp" dentro del archivo con los métodos anteriores 100 veces estos resultados.
Entonces, mi cuarto método es definitivamente el ganador, pero, de manera realista, si un archivo de 3.6 millones de caracteres 100 veces solo tomaba 1586ms como el peor de los casos, entonces todo esto es bastante insignificante.
Por cierto, también escaneé el 'd' char en el archivo de 3,6 millones de caracteres con 100 veces los métodos CountSubstr y CountChar. Resultados ...
El método original de carteles es muy malo para agujas de un solo personaje en un gran pajar de acuerdo con esto.
Nota: Todos los valores se actualizaron a la versión de lanzamiento. Accidentalmente olvidé construir en modo Release la primera vez que publiqué esto. Algunas de mis declaraciones han sido enmendadas.
fuente
Una función genérica para ocurrencias de cadenas:
fuente
Una variación en la respuesta de Richard Watson, un poco más rápido con la mejora de la eficiencia, ¡cuantas más veces se produce el char en la cadena y menos código!
Aunque debo decir que, sin probar exhaustivamente cada escenario, vi una mejora de velocidad muy significativa al usar:
fuente
Necesitaba hacer algo similar para probar las declaraciones condicionales de una cadena.
Reemplacé lo que estaba buscando con un solo personaje y conté las instancias del único personaje.
Obviamente, el carácter único que está utilizando deberá verificarse para que no exista en la cadena antes de que esto ocurra para evitar conteos incorrectos.
fuente
Cadena en cadena:
Encuentra "etc" en ".. JD JD JD JD etc. y etc. JDJDJDJDJDJDJDJD y etc."
Verifique el rendimiento antes de descartar este como poco sólido / torpe ...
fuente
Mi primera toma me dio algo como:
La aguja en un enfoque de pajar que usa reemplazo y división rinde más de 21 segundos, mientras que esto toma aproximadamente 15.2.
Edite después de agregar un bit que agregaría
substring.Length - 1
al charIndex (como debería), es de 11.6 segundos.Edición 2: utilicé una cadena que tenía 26 cadenas de dos caracteres, aquí están los tiempos actualizados a los mismos textos de muestra:
Aguja en un pajar (versión de OP): 7.8 segundos
Mecanismo sugerido: 4.6 segundos.
Edición 3: agregando el caso de esquina de un solo carácter, pasó a 1.2 segundos.
Edición 4: Para el contexto: se usaron 50 millones de iteraciones.
fuente
Pensé que lanzaría mi método de extensión al ring (ver comentarios para más información). No he hecho ninguna marca formal de banco, pero creo que tiene que ser muy rápido para la mayoría de los escenarios.
EDITAR: OK, así que esta pregunta SO me hizo preguntarme cómo se compararía el rendimiento de nuestra implementación actual con algunas de las soluciones presentadas aquí. Decidí hacer una pequeña marca de banco y descubrí que nuestra solución estaba muy en línea con el rendimiento de la solución proporcionada por Richard Watson hasta que realiza una búsqueda agresiva con cadenas grandes (100 Kb +), subcadenas grandes (32 Kb + ) y muchas repeticiones integradas (10K +). En ese momento, nuestra solución fue alrededor de 2X a 4X más lenta. Dado esto y el hecho de que realmente nos gusta la solución presentada por Richard Watson, hemos refactorizado nuestra solución en consecuencia. Solo quería que esto estuviera disponible para cualquiera que pudiera beneficiarse de él.
Nuestra solución original:
Y aquí está nuestra solución revisada:
fuente
fuente
Simplemente verifica cada carácter en la cadena, si el carácter es el carácter que está buscando, agregue uno para contar.
fuente
Si visita esta página web , se comparan 15 formas diferentes de hacerlo, incluido el uso de bucles paralelos.
Parece que la forma más rápida es usar un solo bucle for roscado (si tiene una versión .Net <4.0) o un bucle paralelo .for (si usa .Net> 4.0 con miles de comprobaciones).
Suponiendo que "ss" es su Cadena de búsqueda, "ch" es su matriz de caracteres (si tiene más de un carácter que está buscando), aquí está la esencia básica del código que tuvo el tiempo de ejecución más rápido de un solo subproceso:
También se proporciona el código fuente de referencia para que pueda ejecutar sus propias pruebas.
fuente
Esto es para contar la ocurrencia del personaje. Para este ejemplo, la salida será "a4b4j3"
fuente
Para el caso de un delimitador de cadena (no para el caso de char, como dice el sujeto):
string source = "@@@ once @@@ upon @@@ a @@@ time @@@";
int count = source.Split (new [] {"@@@"}, StringSplitOptions.RemoveEmptyEntries) .Length - 1;
El delimitador natural del valor fuente original del póster ("/ once / upon / a / time /") es un char '/' y las respuestas explican la opción source.Split (char []) aunque ...
fuente
usando System.Linq;
int CountOf => "A :: BC :: D" .Split ("::"). Longitud - 1;
fuente