Pregunta

Estoy escribiendo un editor de texto y necesito proporcionar un recuento de palabras en vivo. Ahora mismo estoy usando este método de extensión:

 public static int WordCount(this string s)
    {
        s = s.TrimEnd();
        if (String.IsNullOrEmpty(s)) return 0;
        int count = 0;
        bool lastWasWordChar = false;
        foreach (char c in s)
        {
            if (Char.IsLetterOrDigit(c) || c == '_' || c == '\'' || c == '-')
            {
                lastWasWordChar = true;
                continue;
            }
            if (lastWasWordChar)
            {
                lastWasWordChar = false;
                count++;
            }
        }
        if (!lastWasWordChar) count--;
        return count + 1;
    }

Lo tengo configurado para que el recuento de palabras se ejecute en el texto del RichTextBox cada décima de segundo (si el inicio de selección es diferente de lo que era la última vez que se ejecutó el método). El problema es que el recuento de palabras se vuelve lento cuando se trabaja en archivos muy largos. Para resolver esto, estoy pensando en que el recuento de palabras solo se ejecute en el párrafo actual, registrando el recuento de palabras cada vez y comparándolo con lo que el recuento de palabras era la última vez que se ejecutó el recuento de palabras. Luego agregaría la diferencia entre los dos al recuento total de palabras. Hacer esto causaría muchas complicaciones (si el usuario pega, si el usuario elimina un párrafo, etc.) ¿Es esta una forma lógica de mejorar mi recuento de palabras? ¿O hay algo que no sé qué lo mejoraría?

Editar: ¿Funcionaría ejecutar el recuento de palabras en un hilo diferente? No sé mucho sobre hilos, investigaré.

Texto de muestra que utilicé:

¿Fue útil?

Solución

Podrías hacer un recuento de palabras más simple basado en el espacio blanco:

public static int WordCount(this string s)
{
  return s.Split(new char[] {' '}, 
    StringSplitOptions.RemoveEmptyEntries).Length;
}

MSDN proporciona este ejemplo, debería darle un recuento de palabras preciso mucho más rápido en archivos grandes.

Otros consejos

También puede usar una regex muy simple que busca al menos un carácter de palabra y/o apóstrofe para capturar las contracciones:

public static int WordCount(this string s) 
{
    return Regex.Matches(s, @"[\w']+").Count;
}

Esto devolverá 2141 partidos (que en realidad es más correcto que la palabra en este caso porque la palabra cuenta el asterisco único como una palabra en la oración "apuñalando a * con su dedo").

Su método es en realidad más rápido que el propuesto String.Split Método, casi tres veces más rápido en X86 y más de dos veces más rápido en X64 de hecho. Sospecho que JIT está jugando con sus horarios, siempre ejecute sus microbistres dos veces, ya que JIT ocupará el gran mayoría del tiempo durante tu primera carrera. Y porqué String.Split ha sido Ngen'd, no es necesario compilarlo con el código nativo y, por lo tanto, parecerá ser más rápido.

Sin mencionar que también es más preciso, String.Split contará 7 palabras aquí:

prueba: esta es una prueba

También tiene sentido, String.Split No realiza ninguna magia y me sorprendería mucho si la creación de una variedad de muchas cuerdas sería más rápida que simplemente iterar sobre los caracteres individuales de la cuerda. Aparentemente, la excepción de una cadena ha sido altamente optimizada mientras lo intenté unsafe aritmética de puntero y en realidad era un poquito más lento que un simple foreach. Realmente dudo que haya alguna forma de hacerlo más rápido, aparte de ser inteligente sobre qué secciones de su texto necesitan cuentas de palabras.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top