|
1 |
| -# Lookahead and lookbehind |
| 1 | +# Lookahead y lookbehind (revisar delante/detrás) |
2 | 2 |
|
3 |
| -Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern. |
| 3 | +A veces necesitamos buscar únicamente aquellas coincidencias donde un patrón es precedido o seguido por otro patrón. |
4 | 4 |
|
5 |
| -There's a special syntax for that, called "lookahead" and "lookbehind", together referred to as "lookaround". |
| 5 | +Existe una sintaxis especial para eso llamadas "lookahead" y "lookbehind" ("ver delante" y "ver detrás"), juntas son conocidas como "lookaround" ("ver alrededor"). |
6 | 6 |
|
7 |
| -For the start, let's find the price from the string like `subject:1 turkey costs 30€`. That is: a number, followed by `subject:€` sign. |
| 7 | +Para empezar, busquemos el precio de la cadena siguiente `subject:1 pavo cuesta 30€`. Eso es: un número, seguido por el signo `subject:€`. |
8 | 8 |
|
9 | 9 | ## Lookahead
|
10 | 10 |
|
11 |
| -The syntax is: `pattern:X(?=Y)`, it means "look for `pattern:X`, but match only if followed by `pattern:Y`". There may be any pattern instead of `pattern:X` and `pattern:Y`. |
| 11 | +La sintaxis es: `pattern:X(?=Y)`. Esto significa "buscar `pattern:X`, pero considerarlo una coincidencia solo si es seguido por `pattern:Y`". Puede haber cualquier patrón en `pattern:X` y `pattern:Y`. |
12 | 12 |
|
13 |
| -For an integer number followed by `subject:€`, the regexp will be `pattern:\d+(?=€)`: |
| 13 | +Para un número entero seguido de `subject:€`, la expresión regular será `pattern:\d+(?=€)`: |
14 | 14 |
|
15 | 15 | ```js run
|
16 |
| -let str = "1 turkey costs 30€"; |
| 16 | +let str = "1 pavo cuesta 30€"; |
17 | 17 |
|
18 |
| -alert( str.match(/\d+(?=€)/) ); // 30, the number 1 is ignored, as it's not followed by € |
| 18 | +alert( str.match(/\d+(?=€)/) ); // 30, el número 1 es ignorado porque no está seguido de € |
19 | 19 | ```
|
20 | 20 |
|
21 |
| -Please note: the lookahead is merely a test, the contents of the parentheses `pattern:(?=...)` is not included in the result `match:30`. |
| 21 | +Tenga en cuenta que "lookahead" es solamente una prueba, lo contenido en los paréntesis `pattern:(?=...)` no es incluido en el resultado `match:30`. |
22 | 22 |
|
23 |
| -When we look for `pattern:X(?=Y)`, the regular expression engine finds `pattern:X` and then checks if there's `pattern:Y` immediately after it. If it's not so, then the potential match is skipped, and the search continues. |
| 23 | +Cuando buscamos `pattern:X(?=Y)`, el motor de expresión regular encuentra `pattern:X` y luego verifica si existe `pattern:Y` inmediatamente después de él. Si no existe, entonces la coincidencia potencial es omitida y la búsqueda continúa. |
24 | 24 |
|
25 |
| -More complex tests are possible, e.g. `pattern:X(?=Y)(?=Z)` means: |
| 25 | +Es posible realizar pruebas más complejas, por ejemplo `pattern:X(?=Y)(?=Z)` significa: |
26 | 26 |
|
27 |
| -1. Find `pattern:X`. |
28 |
| -2. Check if `pattern:Y` is immediately after `pattern:X` (skip if isn't). |
29 |
| -3. Check if `pattern:Z` is also immediately after `pattern:X` (skip if isn't). |
30 |
| -4. If both tests passed, then the `pattern:X` is a match, otherwise continue searching. |
| 27 | +1. Encuentra `pattern:X`. |
| 28 | +2. Verifica si `pattern:Y` está inmediatamente después de `pattern:X` (omite si no es así). |
| 29 | +3. Verifica si `pattern:Z` está también inmediatamente después de `pattern:X` (omite si no es así). |
| 30 | +4. Si ambas verificaciones se cumplen, el `pattern:X` es una coincidencia. De lo contrario continúa buscando. |
31 | 31 |
|
32 |
| -In other words, such pattern means that we're looking for `pattern:X` followed by `pattern:Y` and `pattern:Z` at the same time. |
| 32 | +En otras palabras, dicho patrón significa que estamos buscando por `pattern:X` seguido de `pattern:Y` y `pattern:Z` al mismo tiempo. |
33 | 33 |
|
34 |
| -That's only possible if patterns `pattern:Y` and `pattern:Z` aren't mutually exclusive. |
| 34 | +Eso es posible solamente si los patrones `pattern:Y` y `pattern:Z` no se excluyen mutuamente. |
35 | 35 |
|
36 |
| -For example, `pattern:\d+(?=\s)(?=.*30)` looks for `pattern:\d+` that is followed by a space `pattern:(?=\s)`, and there's `30` somewhere after it `pattern:(?=.*30)`: |
| 36 | +Por ejemplo, `pattern:\d+(?=\s)(?=.*30)` busca un `pattern:\d+` que sea seguido por un espacio `pattern:(?=\s)` y que también tenga un `30` en algún lugar después de él `pattern:(?=.*30)`: |
37 | 37 |
|
38 | 38 | ```js run
|
39 |
| -let str = "1 turkey costs 30€"; |
| 39 | +let str = "1 pavo cuesta 30€"; |
40 | 40 |
|
41 | 41 | alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1
|
42 | 42 | ```
|
43 | 43 |
|
44 |
| -In our string that exactly matches the number `1`. |
| 44 | +En nuestra cadena eso coincide exactamente con el número `1`. |
45 | 45 |
|
46 |
| -## Negative lookahead |
| 46 | +## Lookahead negativo |
47 | 47 |
|
48 |
| -Let's say that we want a quantity instead, not a price from the same string. That's a number `pattern:\d+`, NOT followed by `subject:€`. |
| 48 | +Digamos que queremos una cantidad, no un precio de la misma cadena. Eso es el número `pattern:\d+` NO seguido por `subject:€`. |
49 | 49 |
|
50 |
| -For that, a negative lookahead can be applied. |
| 50 | +Para eso se puede aplicar un "lookahead negativo". |
51 | 51 |
|
52 |
| -The syntax is: `pattern:X(?!Y)`, it means "search `pattern:X`, but only if not followed by `pattern:Y`". |
| 52 | +La sintaxis es: `pattern:X(?!Y)`, que significa "busca `pattern:X`, pero solo si no es seguido por `pattern:Y`". |
53 | 53 |
|
54 | 54 | ```js run
|
55 |
| -let str = "2 turkeys cost 60€"; |
| 55 | +let str = "2 pavos cuestan 60€"; |
56 | 56 |
|
57 |
| -alert( str.match(/\d+\b(?!€)/g) ); // 2 (the price is not matched) |
| 57 | +alert( str.match(/\d+\b(?!€)/g) ); // 2 (el precio es omitido) |
58 | 58 | ```
|
59 | 59 |
|
60 | 60 | ## Lookbehind
|
61 | 61 |
|
62 |
| -Lookahead allows to add a condition for "what follows". |
| 62 | +"lookahead" permite agregar una condición para "lo que sigue". |
63 | 63 |
|
64 |
| -Lookbehind is similar, but it looks behind. That is, it allows to match a pattern only if there's something before it. |
| 64 | +"Lookbehind" es similar. Permite coincidir un patrón solo si hay algo anterior a él. |
65 | 65 |
|
66 |
| -The syntax is: |
67 |
| -- Positive lookbehind: `pattern:(?<=Y)X`, matches `pattern:X`, but only if there's `pattern:Y` before it. |
68 |
| -- Negative lookbehind: `pattern:(?<!Y)X`, matches `pattern:X`, but only if there's no `pattern:Y` before it. |
| 66 | +La sintaxis es: |
| 67 | +- Lookbehind positivo: `pattern:(?<=Y)X`, coincide `pattern:X`, pero solo si hay `pattern:Y` antes de él. |
| 68 | +- Lookbehind negativo: `pattern:(?<!Y)X`, coincide `pattern:X`, pero solo si no hay `pattern:Y` antes de él. |
69 | 69 |
|
70 |
| -For example, let's change the price to US dollars. The dollar sign is usually before the number, so to look for `$30` we'll use `pattern:(?<=\$)\d+` -- an amount preceded by `subject:$`: |
| 70 | +Por ejemplo, cambiemos el precio a dólares estadounidenses. El signo de dólar usualmente va antes del número, entonces para buscar `$30` usaremos `pattern:(?<=\$)\d+`: una cantidad precedida por `subject:$`: |
71 | 71 |
|
72 | 72 | ```js run
|
73 |
| -let str = "1 turkey costs $30"; |
| 73 | +let str = "1 pavo cuesta $30"; |
74 | 74 |
|
75 |
| -// the dollar sign is escaped \$ |
76 |
| -alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number) |
| 75 | +// el signo de dólar se ha escapado \$ |
| 76 | +alert( str.match(/(?<=\$)\d+/) ); // 30 (omite los números aislados) |
77 | 77 | ```
|
78 | 78 |
|
79 |
| -And, if we need the quantity -- a number, not preceded by `subject:$`, then we can use a negative lookbehind `pattern:(?<!\$)\d+`: |
| 79 | +Y si necesitamos la cantidad (un número no precedida por `subject:$`), podemos usar "lookbehind negativo" `pattern:(?<!\$)\d+`: |
80 | 80 |
|
81 | 81 | ```js run
|
82 |
| -let str = "2 turkeys cost $60"; |
| 82 | +let str = "2 pavos cuestan $60"; |
83 | 83 |
|
84 |
| -alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (the price is not matched) |
| 84 | +alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (el precio es omitido) |
85 | 85 | ```
|
86 | 86 |
|
87 |
| -## Capturing groups |
| 87 | +## Atrapando grupos |
88 | 88 |
|
89 |
| -Generally, the contents inside lookaround parentheses does not become a part of the result. |
| 89 | +Generalmente, los contenidos dentro de los paréntesis de "lookaround" (ver alrededor) no se convierten en parte del resultado. |
90 | 90 |
|
91 |
| -E.g. in the pattern `pattern:\d+(?=€)`, the `pattern:€` sign doesn't get captured as a part of the match. That's natural: we look for a number `pattern:\d+`, while `pattern:(?=€)` is just a test that it should be followed by `subject:€`. |
| 91 | +Ejemplo en el patrón `pattern:\d+(?=€)`, el signo `pattern:€` no es capturado como parte de la coincidencia. Eso es esperado: buscamos un número `pattern:\d+`, mientras `pattern:(?=€)` es solo una prueba que indica que debe ser seguida por `subject:€`. |
92 | 92 |
|
93 |
| -But in some situations we might want to capture the lookaround expression as well, or a part of it. That's possible. Just wrap that part into additional parentheses. |
| 93 | +Pero en algunas situaciones nosotros podríamos querer capturar también la expresión en "lookaround", o parte de ella. Eso es posible: solo hay que rodear esa parte con paréntesis adicionales. |
94 | 94 |
|
95 |
| -In the example below the currency sign `pattern:(€|kr)` is captured, along with the amount: |
| 95 | +En los ejemplos de abajo el signo de divisa `pattern:(€|kr)` es capturado junto con la cantidad: |
96 | 96 |
|
97 | 97 | ```js run
|
98 |
| -let str = "1 turkey costs 30€"; |
99 |
| -let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr |
| 98 | +let str = "1 pavo cuesta 30€"; |
| 99 | +let regexp = /\d+(?=(€|kr))/; // paréntesis extra alrededor de €|kr |
100 | 100 |
|
101 | 101 | alert( str.match(regexp) ); // 30, €
|
102 | 102 | ```
|
103 | 103 |
|
104 |
| -And here's the same for lookbehind: |
| 104 | +Lo mismo para "lookbehind": |
105 | 105 |
|
106 | 106 | ```js run
|
107 |
| -let str = "1 turkey costs $30"; |
| 107 | +let str = "1 pavo cuesta $30"; |
108 | 108 | let regexp = /(?<=(\$|£))\d+/;
|
109 | 109 |
|
110 | 110 | alert( str.match(regexp) ); // 30, $
|
111 | 111 | ```
|
112 | 112 |
|
113 |
| -## Summary |
| 113 | +## Resumen |
114 | 114 |
|
115 |
| -Lookahead and lookbehind (commonly referred to as "lookaround") are useful when we'd like to match something depending on the context before/after it. |
| 115 | +Lookahead y lookbehind (en conjunto conocidos como "lookaround") son útiles cuando queremos hacer coincidir algo dependiendo del contexto antes/después. |
116 | 116 |
|
117 |
| -For simple regexps we can do the similar thing manually. That is: match everything, in any context, and then filter by context in the loop. |
| 117 | +Para expresiones regulares simples podemos hacer lo mismo manualmente. Esto es: coincidir todo, en cualquier contexto, y luego filtrar por contexto en el bucle. |
118 | 118 |
|
119 |
| -Remember, `str.match` (without flag `pattern:g`) and `str.matchAll` (always) return matches as arrays with `index` property, so we know where exactly in the text it is, and can check the context. |
| 119 | +Recuerda, `str.match` (sin el indicador `pattern:g`) y `str.matchAll` (siempre) devuelven las coincidencias como un array con la propiedad `index`, así que sabemos exactamente dónde están dentro del texto y podemos comprobar su contexto. |
120 | 120 |
|
121 |
| -But generally lookaround is more convenient. |
| 121 | +Pero generalmente "lookaround" es más conveniente. |
122 | 122 |
|
123 |
| -Lookaround types: |
| 123 | +Tipos de "lookaround": |
124 | 124 |
|
125 |
| -| Pattern | type | matches | |
| 125 | +| Patrón | Tipo | Coincidencias | |
126 | 126 | |--------------------|------------------|---------|
|
127 |
| -| `X(?=Y)` | Positive lookahead | `pattern:X` if followed by `pattern:Y` | |
128 |
| -| `X(?!Y)` | Negative lookahead | `pattern:X` if not followed by `pattern:Y` | |
129 |
| -| `(?<=Y)X` | Positive lookbehind | `pattern:X` if after `pattern:Y` | |
130 |
| -| `(?<!Y)X` | Negative lookbehind | `pattern:X` if not after `pattern:Y` | |
| 127 | +| `X(?=Y)` | lookahead positivo | `pattern:X` si está seguido por `pattern:Y` | |
| 128 | +| `X(?!Y)` | lookahead negativo | `pattern:X` si no está seguido por `pattern:Y` | |
| 129 | +| `(?<=Y)X` | lookbehind positivo | `pattern:X` si está después de `pattern:Y` | |
| 130 | +| `(?<!Y)X` | lookbehind negativo | `pattern:X` si no está después de `pattern:Y` | |
0 commit comments