Contador de palabras JavaScript: cómo construirlo y evitar los errores comunes

Aprende cómo construir un contador de palabras JavaScript con expresiones regulares, contar párrafos con máquina de estados y evitar errores con Unicode y valores undefined.

Por Contador de Palabras11 sept 2026
Contenido

Hace poco planteé un ejercicio para crear un contador de palabras y el problema que me surgía en la forma de contar las palabras correctamente. La gente se puso a proponer soluciones, pero en realidad había algo fundamentalmente malo con lo que todas intentaban hacer. Esas propuestas tenían un error importante, y aquí te explico por qué.

Espacios, saltos de línea y tabulaciones son problemáticos al dividir por ellos. El método split() nos permite dividir una cadena por espacios o por otro tipo de separadores. Ese es el primer paso del ejercicio, pero luego surge el problema. Si dividimos un texto por espacios, podremos tener entradas vacías si existen varios espacios seguidos. De hecho también podría haber otros tipos de espaciadores como tabulaciones o saltos de línea, y todo eso hace que este enfoque no funcione bien cuando queremos contar palabras de verdad.

Eso ocasiona dos cosas:

El resultado de split será incorrecto en textos reales

La confusión entre contar caracteres y contar palabras. Es muy habitual ver ejemplos que cuentan cuántos caracteres hay (es decir, la longitud) cuando realmente queremos contar palabras.

La solución ideal para contar palabras es usar expresiones regulares. En lugar de hacer un split(), vamos a usar una expresión regular que haga justo lo contrario. Para ello tenemos esta función llamada contarPalabras():

function contarPalabras(texto) {

const m = texto.match(/\S+/g);

return m ? m.length : 0;

}

Aquí usamos texto.match(/\S+/g). ¿Por qué? Pues porque \S+ significa "secuencias de caracteres que no sean espacio", y gracias a esa expresión buscamos precisamente ese tipo de fragmentos.

En este caso, el uso de la expresión regular hace que las tabulaciones (\t), saltos de línea (\n) y demás formas de hacer "espaciadores" no entren en cuenta, y esto evita esos problemas. Así, si quiero contar palabras de una frase, puedo aplicar esa función directamente al texto que tenga esa frase, y obtendré correctamente el número de palabras. Esta es sin duda la forma más robusta de realizar el ejercicio.

Contar párrafos correctamente

Para contar párrafos hay otra forma de razonamiento. Aquí, la idea es contar cuántos párrafos tiene el texto. Por ejemplo, si tengo un texto así:

Este es el primer párrafo.

Segundo párrafo.

Y aquí está el tercero.

Entonces deberíamos contar tres párrafos. El primero termina en un salto de línea, el segundo tiene uno, pero en la entrada hay dos salto de línea consecutivos. Eso complica la división en párrafos, ya que si simplemente dividimos por saltos de línea tendremos cuatro partes: la primera, las líneas vacías, y la última.

Aquí es donde entra la idea de una máquina de estados. La idea es crear una variable booleana, enParrafo, que inicializaremos a false. Luego dividimos el texto por saltos de línea (\n) y recorremos cada elemento de la lista obtenida. Para cada una de ellas, realizamos lo siguiente:

Si encontramos una línea vacía, entonces cambiamos enParrafo a false.

Si encontramos una línea no vacía, comprobamos si estamos dentro de un párrafo (si enParrafo es true). Si no estamos, entonces comenzamos un nuevo párrafo. Y además incrementamos nuestro contador.

Con ese sistema podemos detectar todos los párrafos correctos. La ventaja de esta forma de razonamiento es que nos permite evitar sobrecontar párrafos.

String.length y Unicode

Hay un detalle importante. La propiedad String.length devuelta por el objeto String de JavaScript es muy útil para calcular cuántos caracteres tiene un texto, pero no siempre corresponde al número de caracteres visibles que mostramos. El motivo es que Unicode no funciona como ASCII.

En Unicode, hay valores de código Unicode. Cada carácter se puede representar como uno o más puntos de código Unicode. Aun así, los valores de UTF-16 que utilizamos en JavaScript pueden representar algunos puntos de código Unicode como dos valores de código. Esto ocurre por ejemplo con algunos emojis u otros caracteres especiales de idiomas orientales como chino, japonés, coreano. Por ejemplo, muchos de estos últimos ocupan 2 unidades de código UTF-16, aunque visualmente parecen un solo caracter.

Pero hay otra limitación: cuando un string contiene algún carácter Unicode, la longitud (String.length) devuelve un valor que indica cuántos valores de código UTF-16 están presentes, no cuántos puntos de código Unicode. Eso puede causar que, por ejemplo, los emojis cuenten como 2 y no como 1.

Debemos recordar que desde julio de 2015 el valor de String.length está disponible ampliamente, por lo que puedes utilizarla sin problemas. Pero debes saber que no equivale ni al número de puntos de código Unicode, ni al número real de caracteres que muestras en pantalla. Es algo a tener en cuenta si necesitas procesar texto con Unicode en JavaScript.

Antes de operar sobre valores undefined

Como sabes, acceder a .length sobre un objeto undefined lanzará un TypeError:

Uncaught TypeError: Cannot read properties of undefined (reading 'length')

window.noExiste === undefined;

Así, cuando tratemos de obtener la longitud de un texto antes de asegurarnos de que dicho texto existe, podemos acabar lanzando excepciones inesperadas.

Por supuesto, esto pasa con cualquier otro acceso a una propiedad de un objeto undefined. Es importante prevenir ese error para que tu programa esté libre de fallos potenciales.

Lecturas relacionadas