Logotipo de Zephyrnet

Java: cuenta el número de ocurrencias de palabras en una cadena

Fecha:

Introducción

Contar el número de ocurrencias de palabras en una cadena es una tarea bastante fácil, pero tiene varios enfoques para hacerlo. También debe tener en cuenta la eficiencia del método, ya que normalmente querrá emplear herramientas automatizadas cuando no desee realizar trabajo manual, es decir, cuando el espacio de búsqueda sea grande.

En esta guía, aprenderá cómo contar el número de ocurrencias de palabras en una cadena en Java:

String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";

Buscaremos el número de ocurrencias del targetWord, utilizando String.split(), Collections.frequency() y expresiones regulares.

Cuente las apariciones de palabras en una cadena con String.split ()

La forma más sencilla de contar la ocurrencia de una palabra objetivo en una cadena es dividir la cadena en cada palabra e iterar a través de la matriz, incrementando un wordCount en cada partido. Tenga en cuenta que cuando una palabra tiene algún tipo de puntuación a su alrededor, como wants. al final de la oración: la división simple de nivel de palabra tratará correctamente wants y wants. como palabras separadas!

Para evitar esto, puede eliminar fácilmente todos los signos de puntuación de la oración. antes dividirlo:

String[] words = searchText.replaceAll("p{Punct}", "").split(" ");

int wordCount = 0;
for (int i=0; i < words.length; i++)
    if (words[i].equals(targetWord))
        wordCount++;
System.out.println(wordCount);

En for bucle, simplemente iteramos a través de la matriz, verificando si el elemento en cada índice es igual al targetWord. Si lo es, incrementamos el wordCount, que al final de la ejecución, imprime:

2

Cuente las apariciones de palabras en una cadena con Colecciones.frecuencia()

El Collections.frequency() El método proporciona una implementación mucho más limpia y de alto nivel, que abstrae un simple for bucle, y comprueba tanto la identidad (si un objeto is otro objeto) e igualdad (si un objeto es igual a otro objeto, dependiendo de las características cualitativas de ese objeto).

El frequency() El método acepta una lista para buscar y el objeto de destino, y también funciona para todos los demás objetos, donde el comportamiento depende de cómo se implementa el objeto en sí. equals(). En el caso de las cuerdas, equals() cheques para el contenido de la cadena:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

Aquí, hemos convertido la matriz obtenida de split() en un Java ArrayList, usando el ayudante asList() método de la Arrays clase. La operación de reducción frequency() devuelve un entero que indica la frecuencia de targetWord en la lista, y da como resultado:

2

Ocurrencias de palabras en cadenas con Matcher (Expresiones Regulares – RegEx)

Finalmente, puede usar expresiones regulares para buscar patrones y contar la cantidad de patrones coincidentes. Las expresiones regulares están hechas para esto, por lo que es una opción muy natural para la tarea. En Java, el Pattern La clase se utiliza para representar y compilar expresiones regulares, y la Matcher La clase se utiliza para buscar y combinar patrones.

Usando RegEx, podemos codificar la invariancia de la puntuación en la propia expresión, por lo que no hay necesidad de formatear externamente la cadena o eliminar la puntuación, lo cual es preferible para textos grandes donde almacenar otra versión alterada en la memoria puede ser costoso:

Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));

Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);

int wordCount = 0;
while (matcher.find())
    wordCount++;

System.out.println(wordCount);

Esto también resulta en:

2

Punto de referencia de eficiencia

Entonces, ¿cuál es el más eficiente? Hagamos un pequeño benchmark:

int runs = 100000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithSplit(searchText, targetWord);
}

long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
  for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithCollections(searchText, targetWord);
}

long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithRegex(searchText, targetWord);
}

long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));

Cada método se ejecutará 100000 veces (cuanto mayor sea el número, menor será la varianza y los resultados debido al azar, debido a la ley de los grandes números). Ejecutar este código da como resultado:

Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds

Sin embargo, ¿qué sucede si hacemos que la búsqueda sea más costosa desde el punto de vista computacional al hacerla más grande? Generemos una oración sintética:

List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();

for (int i = 0; i < 100; i++) {
    searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);

Esto crea una cadena con el contenido:

hello world hello world hello world hello ...

Consulte nuestra guía práctica y práctica para aprender Git, con las mejores prácticas, los estándares aceptados por la industria y la hoja de trucos incluida. Deja de buscar en Google los comandos de Git y, de hecho, aprenden ella!

Ahora, si tuviéramos que buscar "hola" o "mundo", habría muchas más coincidencias que las dos anteriores. ¿Cómo funcionan nuestros métodos ahora en el punto de referencia?

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

¡Ahora, la división de matrices sale más rápido! En general, los puntos de referencia dependen de varios factores, como el espacio de búsqueda, la palabra objetivo, etc. y su caso de uso personal puede ser diferente del punto de referencia.

Consejo: Pruebe los métodos en su propio texto, anote los tiempos y elija el más eficiente y elegante para usted.

Conclusión

En esta breve guía, hemos echado un vistazo a cómo contar las apariciones de palabras para una palabra de destino, en una cadena en Java. Comenzamos dividiendo la cadena y usando un contador simple, seguido de usar el Collections clase auxiliar y, por último, el uso de expresiones regulares.

Al final, evaluamos los métodos y notamos que el rendimiento no es lineal y depende del espacio de búsqueda. Para textos de entrada más largos con muchas coincidencias, dividir matrices parece ser el más eficaz. Pruebe los tres métodos por su cuenta y elija el de mayor rendimiento.

punto_img

Información más reciente

punto_img