Skip to content

Commit e7c6c97

Browse files
authored
Merge pull request #487 from joaquinelio/sticky
sticky 9 16 update - cierra issue #440
2 parents c94c928 + 37bde37 commit e7c6c97

File tree

1 file changed

+33
-22
lines changed

1 file changed

+33
-22
lines changed

9-regular-expressions/16-regexp-sticky/article.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,52 @@
33

44
EL indicador `pattern:y` permite realizar la búsqueda en una posición dada en el string de origen.
55

6-
Para entender el caso de uso del indicador `pattern:y`, y ver lo notable que es, exploremos un ejemplo práctico.
6+
Para entender el caso de uso del indicador `pattern:y` exploremos un ejemplo práctico.
77

8-
Una tarea común para regexps es el "Análisis léxico": tenemos un texto, por ej. en un lenguaje de programación, y analiza sus elementos estructurales.
9-
10-
Por ejemplo, HTML tiene etiquetas y atributos, el código JavaScript tiene funciones, variables, etc.
8+
Una tarea común para regexps es el "Análisis léxico": tomar un texto (como el de un lenguaje de programación), y analizar sus elementos estructurales. Por ejemplo, HTML tiene etiquetas y atributos, el código JavaScript tiene funciones, variables, etc.
119

1210
Escribir analizadores léxicos es un área especial, con sus propias herramientas y algoritmos, así que no profundizaremos en ello; pero existe una tarea común: leer algo en una posición dada.
1311

1412
Por ej. tenemos una cadena de código `subject:let varName = "value"`, y necesitamos leer el nombre de su variable, que comienza en la posición `4`.
1513

1614
Buscaremos el nombre de la variable usando regexp `pattern:\w+`. En realidad, el nombre de la variable de JavaScript necesita un regexp un poco más complejo para un emparejamiento más preciso, pero aquí eso no importa.
1715

18-
Una llamada a `str.match(/\w+/)` solo encontrará la primera palabra de la línea, o todas las palabras con el indicador `pattern:g`. Pero solo necesitamos una palabra en la posición `4`.
16+
Una llamada a `str.match(/\w+/)` solo encontrará la primera palabra de la línea (`let`). No es la que queremos.
17+
Podríamos añadir el indicador `pattern:g`, pero al llamar a `str.match(/\w+/g)` buscará todas las palabras del texto y solo necesitamos una y en la posición `4`. De nuevo, no es lo que necesitamos.
18+
19+
**Entonces, ¿cómo buscamos exactamente en un posición deterninada?**
1920

20-
Para buscar desde la posición dada, usamos el método `regexp.exec(str)`.
21+
Usemos el método `regexp.exec(str)`.
2122

22-
`regexp` no tiene indicadores `pattern:g` o `pattern:y`, entonces este método busca la primera coincidencia en el string `str`, exactamente como `str.match(regexp)`. Un caso tan simple sin indicadores no nos interesa aquí.
23+
Para un `regexp` sin los indicadores `pattern:g` y `pattern:y`, este método busca la primera coincidencia y funciona exactamente igual a `str.match(regexp)`.
2324

24-
Si existe el indicador `pattern:g`, realiza la búsqueda en el string `str` empezando desde la posición almacenada en su propiedad `regexp.lastIndex`. Y si encuentra una coincidencia, establece `regexp.lastIndex` en el index inmediatamente después del emparejamiento.
25+
...Pero si existe el indicador `pattern:g`, realiza la búsqueda en `str` empezando desde la posición almacenada en su propiedad `regexp.lastIndex`. Y si encuentra una coincidencia, establece `regexp.lastIndex` en el index inmediatamente posterior a la coincidencia.
2526

26-
Cuando un regex es creado, su `lastIndex` es `0`.
27+
En otras palabras, `regexp.lastIndex` funciona como punto de partida para la búsqueda, cada llamada lo reestablece a un nuevo valor: el posterior a la última coincidencia.
2728

2829
Entonces, llamadas sucesivas a `regexp.exec(str)` devuelve coincidencias una después de la otra.
2930

3031
Un ejemplo (con el indicador `pattern:g`):
3132

3233
```js run
33-
let str = 'let varName';
34-
34+
let str = 'let varName'; // encontremos todas las palabras del string
3535
let regexp = /\w+/g;
36+
3637
alert(regexp.lastIndex); // 0 (inicialmente lastIndex=0)
3738

3839
let word1 = regexp.exec(str);
3940
alert(word1[0]); // let (primera palabra)
40-
alert(regexp.lastIndex); // 3 (Posición posterior al emparejamiento)
41+
alert(regexp.lastIndex); // 3 (Posición posterior a la coincidencia)
4142

4243
let word2 = regexp.exec(str);
4344
alert(word2[0]); // varName (2da palabra)
44-
alert(regexp.lastIndex); // 11 (Posición posterior al emparejamiento)
45+
alert(regexp.lastIndex); // 11 (Posición posterior a la coincidencia)
4546

4647
let word3 = regexp.exec(str);
47-
alert(word3); // null (no más emparejamientos)
48-
alert(regexp.lastIndex); // 0 (reinicia en el final de la búsqueda)
48+
alert(word3); // null (no más coincidencias)
49+
alert(regexp.lastIndex); // 0 (se reinicia al final de la búsqueda)
4950
```
5051

51-
Cada coincidencia es devuelta como un array con grupos y propiedades adicionales.
52-
5352
Podemos conseguir todas las coincidencias en el loop:
5453

5554
```js run
@@ -65,11 +64,13 @@ while (result = regexp.exec(str)) {
6564
}
6665
```
6766

68-
Tal uso de `regexp.exec` es una alternativa al método `str.match bAll`.
67+
Tal uso de `regexp.exec` es una alternativa al método `str.match bAll`, con más control sobre el proceso.
6968

70-
A diferencia de otros métodos, podemos establecer nuestro propio `lastIndex`, para comenzar la búsqueda desde la posición dada.
69+
Volvamos a nuestra tarea.
7170

72-
Por ejemplo, encontremos una palabra, comenzando desde la posición `4`:
71+
Podemos estableceer manualmente `lastIndex` a `4`, para comenzar la búsqueda desde la posición dada.
72+
73+
Como aquí:
7374

7475
```js run
7576
let str = 'let varName = "value"';
@@ -84,8 +85,14 @@ let word = regexp.exec(str);
8485
alert(word); // varName
8586
```
8687

88+
¡Problema resuelto!
89+
8790
Realizamos una búsqueda de `pattern:\w+`, comenzando desde la posición `regexp.lastIndex = 4`.
8891

92+
El resultado es correcto.
93+
94+
...Pero espera, no tan rápido.
95+
8996
Nota que la búsqueda comienza en la posición `lastIndex` y luego sigue adelante. Si no hay ninguna palabra en la posición `lastIndex` pero la hay en algún lugar posterior, entonces será encontrada:
9097

9198
```js run
@@ -94,17 +101,19 @@ let str = 'let varName = "value"';
94101
let regexp = /\w+/g;
95102

96103
*!*
104+
// comenzando desde la posición 3
97105
regexp.lastIndex = 3;
98106
*/!*
99107

100108
let word = regexp.exec(str);
109+
// encuentra coincidencia en la posición 4
101110
alert(word[0]); // varName
102111
alert(word.index); // 4
103112
```
104113

105-
...Así que, con la propiedad `lastIndex` del indicador `pattern:g` se establece la posición inicial de la búsqueda.
114+
Para algunas tareas, incluido el análisis léxico, esto está mal. Necesitamos la coincidencia en la posición exacta, y para ello es el flag `y`.
106115

107-
**El indicador `pattern:y` hace que `regexp.exec` busque exactamente en la posición `lastIndex`, ni antes ni después.**
116+
**El indicador `pattern:y` hace que `regexp.exec` busque "exactamente en" la posición `lastIndex`, no "comenzando en" ella.**
108117

109118
Aquí está la misma búsqueda con el indicador `pattern:y`:
110119

@@ -122,6 +131,8 @@ alert( regexp.exec(str) ); // varName (Una palabra en la posición 4)
122131

123132
Como podemos ver, el `pattern:/\w+/y` de regexp no coincide en la posición `3` (a diferencia del indicador `pattern:g`), pero coincide en la posición `4`.
124133

134+
No solamente es lo que necesitamos, el uso del indicador `pattern:y` mejora el rendimiento.
135+
125136
Imagina que tenemos un texto largo, y no hay coincidencias en él. Entonces la búsqueda con el indicador `pattern:g` irá hasta el final del texto, y esto tomará significativamente más tiempo que la búsqueda con el indicador `pattern:y`.
126137

127138
En tareas tales como el análisis léxico, normalmente hay muchas búsquedas en una posición exacta. Usar el indicador `pattern:y` es la clave para un buen desempeño.

0 commit comments

Comments
 (0)