Anclas en regex: ^, $ y el modo multilínea explicados
^ y $ no coinciden con caracteres, sino con posiciones. Por qué un patrón sin anclas comprueba menos de lo que crees, qué cambia el modificador m, cómo trata el $ de Python un salto de línea final y cuándo usar \A y \z en su lugar.

· 6 min de lectura
/^\d{5}$/
atrapa
- 90210
- 10001
- 02139
- 60614
deja libre
- 9021
- 902100
- ZIP 90210
- 90210-1234
La mayoría de los elementos de una regex coinciden con un carácter. Las anclas coinciden con una posición: el inicio del texto, el final, el hueco entre dos caracteres. No ocupan ningún ancho.
También son lo que más a menudo falta en un patrón de validación. Este artículo cubre ^ y $, lo que cambia el modificador m y los casos límite que varían entre lenguajes. Todos los ejemplos son interactivos, así que edita los patrones y mira cómo cambian las líneas.
01Un patrón sin anclas comprueba menos de lo que crees
Los motores de regex buscan: informan de una coincidencia si el patrón encaja en cualquier parte del texto. Así que un patrón de “código postal de cinco dígitos” sin anclas es en realidad “contiene cinco dígitos seguidos”:
02^ y $
^ coincide al principio del texto y $ al final. Ponlos alrededor del patrón y la entrada entera tendrá que encajar:
/^\d{5}$/Debe coincidir2/2
- 90210
- 02139
No debe4/4
- 9021
- 902100
- ZIP 90210
- 90210-1234
Puedes usar solo una de las dos. ^# significa “empieza por #”, y \.pdf$ significa “termina en .pdf”:
/\.pdf$/Debe coincidir2/2
- report.pdf
- 2026 taxes.pdf
No debe2/2
- report.pdf.exe
- pdf-guide.txt
03Anclas alrededor de una alternancia
| tiene la prioridad más baja de todo el patrón, más baja que las anclas. Así que ^cat|dog$ no significa “exactamente cat o dog”. Significa “empieza por cat, o termina en dog”:
Mete las opciones en un grupo para que las dos anclas se apliquen a ambas:
Esta trampa aparece en código real, en listas de permitidos como ^admin|editor$ que aceptan sin avisar admin-old o not-an-editor.
04Modo multilínea
Por defecto, ^ y $ solo coinciden al principio y al final de todo el texto, aunque contenga saltos de línea. El modificador m hace que coincidan al principio y al final de cada línea:
const text = "apple\nbanana\ncherry";
text.match(/^\w+$/g); // null: "apple\nbanana\ncherry" isn't one word
text.match(/^\w+$/gm); // ["apple", "banana", "cherry"]
Es lo que quieres cuando extraes cosas de un archivo línea a línea. En Python es re.MULTILINE, o (?m) al principio del patrón:
import re
re.findall(r"^#+ .*$", markdown, re.MULTILINE) # every heading line
El modificador solo cambia ^ y $. Un punto sigue sin cruzar un salto de línea. Para eso hay otro modificador, s, que se explica en el artículo sobre modificadores de las regex.
05La trampa del salto de línea final
Aquí los lenguajes difieren. En JavaScript, sin m, $ solo coincide justo al final. En Python, $ también coincide justo antes de un salto de línea situado al final del todo:
import re
re.match(r"^\d{5}$", "90210\n") # matches in Python
re.fullmatch(r"\d{5}", "90210\n") # None
/^\d{5}$/.test("90210\n"); // false in JavaScript
Así que en Python, ^\d{5}$ acepta un código postal con un salto de línea pegado al final. Eso puede importar si el valor va a una base de datos o a un nombre de archivo. Dos soluciones:
- Usa
re.fullmatch(), que tiene que consumir la cadena entera. - Usa
\Ay\Z: en Python,\Aes el inicio absoluto y\Zel final absoluto, sin excepción para el salto de línea. (Ruby, PCRE y Java escriben ese final estricto como\z).
JavaScript no tiene \A ni \z, pero sin el modificador m sus ^ y $ ya se comportan así.
06Los límites de palabra también son anclas
\b es otra ancla de ancho cero: la posición entre un carácter de palabra y uno que no lo es. Así se busca una palabra completa dentro de un texto:
/\bcat\b/Debe coincidir3/3
- the cat sat
- cat
- a cat.
No debe2/2
- concatenate
- cats
07Pruébalo
Atrapa las líneas que son un hashtag y nada más:
Atrapa los hashtags: un # seguido de letras, dígitos o guiones bajos, y nada más.
Objetivos · 0/5 atrapados
- #regexobjetivo
- #100DaysOfCodeobjetivo
- #aobjetivo
- #snake_caseobjetivo
- #2026objetivo
Inocentes · 0 errores
- regexinocente
- ##doubleinocente
- #two wordsinocente
- #inocente
- #dash-edinocente
- a#taginocente
Escribe una regex: el tablero se actualiza mientras escribes.
08Lista de comprobación
- Sin anclas, un patrón solo comprueba que el texto contiene una coincidencia.
^es el inicio y$es el final. Usa los dos para validar.- Agrupa las alternativas dentro de las anclas:
^(cat|dog)$, no^cat|dog$. - El modificador
mhace que^y$funcionen por línea. - En Python,
$admite un salto de línea final. Usare.fullmatch()o\Z. \bancla una palabra completa.
09Sigue practicando
- Levando anclas y Domando líneas son packs de práctica construidos en torno a las anclas.
- La sección de anclas de la guía tiene la lista completa.