Skip to content

Alternation (OR) | #473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

The first idea can be to list the languages with `|` in-between.
La primera idea puede ser listar los idiomas con `|` en el medio.

But that doesn't work right:
Pero eso no funciona bien:

```js run
let regexp = /Java|JavaScript|PHP|C|C\+\+/g;
Expand All @@ -11,18 +11,18 @@ let str = "Java, JavaScript, PHP, C, C++";
alert( str.match(regexp) ); // Java,Java,PHP,C,C
```

The regular expression engine looks for alternations one-by-one. That is: first it checks if we have `match:Java`, otherwise -- looks for `match:JavaScript` and so on.
El motor de expresiones regulares busca las alternancias una por una. Es decir: primero verifica si tenemos `match: Java`, de lo contrario - busca `match: JavaScript` y así sucesivamente.

As a result, `match:JavaScript` can never be found, just because `match:Java` is checked first.
Como resultado, nunca se puede encontrar `match: JavaScript`, solo porque` match: Java` se marca primero.

The same with `match:C` and `match:C++`.
Lo mismo con `match: C` y `match: C ++ `.

There are two solutions for that problem:
Hay dos soluciones para ese problema:

1. Change the order to check the longer match first: `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Merge variants with the same start: `pattern:Java(Script)?|C(\+\+)?|PHP`.
1. Cambiar el orden para comprobar primero la coincidencia más larga: `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Fusionar variantes con el mismo inicio: `pattern:Java(Script)?|C(\+\+)?|PHP`.

In action:
En acción:

```js run
let regexp = /Java(Script)?|C(\+\+)?|PHP/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Find programming languages
# Encuentra lenguajes de programación

There are many programming languages, for instance Java, JavaScript, PHP, C, C++.
Hay muchos lenguajes de programación, por ejemplo, Java, JavaScript, PHP, C, C ++.

Create a regexp that finds them in the string `subject:Java JavaScript PHP C++ C`:
Crea una expresión regular que los encuentre en la cadena `subject:Java JavaScript PHP C++ C`:

```js
let regexp = /your regexp/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

Opening tag is `pattern:\[(b|url|quote)\]`.
La etiqueta de apertura es `pattern:\[(b|url|quote)\]`.

Then to find everything till the closing tag -- let's use the pattern `pattern:.*?` with flag `pattern:s` to match any character including the newline and then add a backreference to the closing tag.
Luego, para encontrar todo hasta la etiqueta de cierre, usemos el patrón`pattern:.*?` con la bandera `pattern:s` para que coincida con cualquier carácter, incluida la nueva línea, y luego agreguemos una referencia inversa a la etiqueta de cierre.

The full pattern: `pattern:\[(b|url|quote)\].*?\[/\1\]`.
El patrón completo: `pattern:\[(b|url|quote)\].*?\[/\1\]`.

In action:
En acción:

```js run
let regexp = /\[(b|url|quote)\].*?\[\/\1\]/gs;
Expand All @@ -20,4 +20,4 @@ let str = `
alert( str.match(regexp) ); // [b]hello![/b],[quote][url]http://google.com[/url][/quote]
```

Please note that besides escaping `pattern:[` and `pattern:]`, we had to escape a slash for the closing tag `pattern:[\/\1]`, because normally the slash closes the pattern.
Tenga en cuenta que además de escapar `pattern:[` y `pattern:]`, tuvimos que escapar de una barra para la etiqueta de cierre `pattern:[\/\1]`, porque normalmente la barra cierra el patrón.
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
# Find bbtag pairs
# Encuentra la pareja bbtag

A "bb-tag" looks like `[tag]...[/tag]`, where `tag` is one of: `b`, `url` or `quote`.
Un "bb-tag" se ve como `[tag]...[/tag]`, donde `tag` es uno de: `b`, `url` o `quote`.

For instance:
Por ejemplo:
```
[b]text[/b]
[url]http://google.com[/url]
```

BB-tags can be nested. But a tag can't be nested into itself, for instance:
BB-tags se puede anidar. Pero una etiqueta no se puede anidar en sí misma, por ejemplo:

```
Normal:
[url] [b]http://google.com[/b] [/url]
[quote] [b]text[/b] [/quote]

Can't happen:
No puede suceder:
[b][b]text[/b][/b]
```

Tags can contain line breaks, that's normal:
Las etiquetas pueden contener saltos de línea, eso es normal:

```
[quote]
[b]text[/b]
[/quote]
```

Create a regexp to find all BB-tags with their contents.
Cree una expresión regular para encontrar todas las BB-tags con su contenido.

For instance:
Por ejemplo:

```js
let regexp = /your regexp/flags;
Expand All @@ -38,7 +38,7 @@ let str = "..[url]http://google.com[/url]..";
alert( str.match(regexp) ); // [url]http://google.com[/url]
```

If tags are nested, then we need the outer tag (if we want we can continue the search in its content):
Si las etiquetas están anidadas, entonces necesitamos la etiqueta externa (si queremos podemos continuar la búsqueda en su contenido):

```js
let regexp = /your regexp/flags;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
The solution: `pattern:/"(\\.|[^"\\])*"/g`.
La solución: `pattern:/"(\\.|[^"\\])*"/g`.

Step by step:
El paso a paso:

- First we look for an opening quote `pattern:"`
- Then if we have a backslash `pattern:\\` (we technically have to double it in the pattern, because it is a special character, so that's a single backslash in fact), then any character is fine after it (a dot).
- Otherwise we take any character except a quote (that would mean the end of the string) and a backslash (to prevent lonely backslashes, the backslash is only used with some other symbol after it): `pattern:[^"\\]`
- ...And so on till the closing quote.
- Primero buscamos una comilla de apertura `pattern:"`
- Entonces, si tenemos una barra invertida `pattern:\\` (tenemos que duplicarla en el patrón porque es un carácter especial), y luego cualquier carácter está bien después de él (un punto).
- De lo contrario, tomamos cualquier carácter excepto una comilla (que significaría el final de la cadena) y una barra invertida (para evitar barras invertidas solitarias, la barra invertida solo se usa con algún otro símbolo después): `pattern:[^"\\]`
- ...Y así sucesivamente hasta la comilla de cierre.

In action:
En acción:

```js run
let regexp = /"(\\.|[^"\\])*"/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# Find quoted strings
# Encuentra cadenas entre comillas

Create a regexp to find strings in double quotes `subject:"..."`.
Crea una expresión regular para encontrar cadenas entre comillas dobles `subject:"..."`.

The strings should support escaping, the same way as JavaScript strings do. For instance, quotes can be inserted as `subject:\"` a newline as `subject:\n`, and the slash itself as `subject:\\`.
Las cadenas deben admitir el escape, de la misma manera que lo hacen las cadenas de JavaScript. Por ejemplo, las comillas se pueden insertar como `subject:\"` ,una nueva línea como `subject:\n`, y la doble sbarra invertida como `subject:\\`.

```js
let str = "Just like \"here\".";
```

Please note, in particular, that an escaped quote `subject:\"` does not end a string.
Tenga en cuenta, en particular, que una comilla escapada `subject:\"` no termina una cadena.

So we should search from one quote to the other ignoring escaped quotes on the way.
Por lo tanto, deberíamos buscar de una comilla a otra (la de cierre), ignorando las comillas escapadas en el camino.

That's the essential part of the task, otherwise it would be trivial.
Esa es la parte esencial de la tarea, de lo contrario sería trivial.

Examples of strings to match:
Ejemplos de cadenas para hacer coincidir:
```js
.. *!*"test me"*/!* ..
.. *!*"Say \"Hello\"!"*/!* ... (escaped quotes inside)
.. *!*"\\"*/!* .. (double slash inside)
.. *!*"\\ \""*/!* .. (double slash and an escaped quote inside)
.. *!*"Say \"Hello\"!"*/!* ... (comillas escapadas dentro)
.. *!*"\\"*/!* .. (doble barra invertida dentro)
.. *!*"\\ \""*/!* .. (doble barra y comilla escapada dentro.)
```

In JavaScript we need to double the slashes to pass them right into the string, like this:
En JavaScript, necesitamos duplicar las barras para pasarlas directamente a la cadena, así:

```js run
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

The pattern start is obvious: `pattern:<style`.
El inicio del patrón es obvio: `pattern:<style`.

...But then we can't simply write `pattern:<style.*?>`, because `match:<styler>` would match it.
...Pero entonces no podemos simplemente escribir `pattern:<style.*?>`, porque `match:<styler>` coincidiría.

We need either a space after `match:<style` and then optionally something else or the ending `match:>`.
Necesitamos un espacio después `match:<style` y luego, opcionalmente, algo más o el final `match:>`.

In the regexp language: `pattern:<style(>|\s.*?>)`.
En el lenguaje de expresión regular: `pattern:<style(>|\s.*?>)`.

In action:
En acción:

```js run
let regexp = /<style(>|\s.*?>)/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Find the full tag
# Encuentra la etiqueta completa

Write a regexp to find the tag `<style...>`. It should match the full tag: it may have no attributes `<style>` or have several of them `<style type="..." id="...">`.
Escriba una expresión regular para encontrar la etiqueta `<style...>`. Debe coincidir con la etiqueta completa: puede no tener atributos `<style>` o tener varios de ellos `<style type="..." id="...">`.

...But the regexp should not match `<styler>`!
...¡Pero la expresión regular no debería coincidir con `<styler>`!

For instance:
Por ejemplo:

```js
let regexp = /your regexp/g;
Expand Down
60 changes: 30 additions & 30 deletions 9-regular-expressions/13-regexp-alternation/article.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
# Alternation (OR) |
# Altarnancia (OR (O)) |

Alternation is the term in regular expression that is actually a simple "OR".
Alternancia es un término en expresión regular que simplemente significa "O".

In a regular expression it is denoted with a vertical line character `pattern:|`.
En una expresión regular se denota con un carácter de línea vertical `pattern:|`.

For instance, we need to find programming languages: HTML, PHP, Java or JavaScript.
Por ejemplo, necesitamos encontrar lenguajes de programación: HTML, PHP, Java o JavaScript.

The corresponding regexp: `pattern:html|php|java(script)?`.
La expresión regular correspondiente es: `pattern:html|php|java(script)?`.

A usage example:
Un ejemplo de uso:

```js run
let regexp = /html|php|css|java(script)?/gi;

let str = "First HTML appeared, then CSS, then JavaScript";
let str = "Primera aparición de HTML, luego CSS, luego JavaScript";

alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript'
```

We already saw a similar thing -- square brackets. They allow to choose between multiple characters, for instance `pattern:gr[ae]y` matches `match:gray` or `match:grey`.
Ya vimos algo similar: corchetes. Permiten elegir entre varios caracteres, por ejemplo `pattern:gr[ae]y` coincide con `match:gray` o `match:grey`.

Square brackets allow only characters or character classes. Alternation allows any expressions. A regexp `pattern:A|B|C` means one of expressions `A`, `B` or `C`.
Los corchetes solo permiten caracteres o conjuntos de caracteres. La alternancia permite cualquier expresión. Una expresión regular `pattern:A|B|C` significa una de las expresiones `A`, `B` o `C`.

For instance:
Por ejemplo:

- `pattern:gr(a|e)y` means exactly the same as `pattern:gr[ae]y`.
- `pattern:gra|ey` means `match:gra` or `match:ey`.
- `pattern:gr(a|e)y` significa exactamente lo mismo que `pattern:gr[ae]y`.
- `pattern:gra|ey` significa `match:gra` o `match:ey`.

To apply alternation to a chosen part of the pattern, we can enclose it in parentheses:
- `pattern:I love HTML|CSS` matches `match:I love HTML` or `match:CSS`.
- `pattern:I love (HTML|CSS)` matches `match:I love HTML` or `match:I love CSS`.
Para aplicar la alternancia a una parte elegida del patrón, podemos encerrarla entre paréntesis:
- `pattern:I love HTML|CSS` coincide con `match:I love HTML` o `match:CSS`.
- `pattern:I love (HTML|CSS)` coincide con `match:I love HTML` o `match:I love CSS`.

## Example: regexp for time
## Ejemplo: Expresión regular para el tiempo

In previous articles there was a task to build a regexp for searching time in the form `hh:mm`, for instance `12:00`. But a simple `pattern:\d\d:\d\d` is too vague. It accepts `25:99` as the time (as 99 minutes match the pattern, but that time is invalid).
En artículos anteriores había una tarea para construir una expresión regular para buscar un horario en la forma `hh:mm`, por ejemplo `12:00`. Pero esta simple expresión `pattern:\d\d:\d\d` es muy vaga. Acepta `25:99` como tiempo (ya que 99 segundos coinciden con el patrón, pero ese tiempo no es válido).

How can we make a better pattern?
¿Cómo podemos hacer un mejor patrón?

We can use more careful matching. First, the hours:
Podemos utilizar una combinación más cuidadosa. Primero, las horas:

- If the first digit is `0` or `1`, then the next digit can be any: `pattern:[01]\d`.
- Otherwise, if the first digit is `2`, then the next must be `pattern:[0-3]`.
- (no other first digit is allowed)
- Si el primer dígito es `0` o `1`, entonces el siguiente dígito puede ser cualquiera: `pattern:[01]\d`.
- De otra manera, si el primer dígito es `2`, entonces el siguiente debe ser `pattern:[0-3]`.
- (no se permite ningún otro dígito)

We can write both variants in a regexp using alternation: `pattern:[01]\d|2[0-3]`.
Podemos escribir ambas variantes en una expresión regular usando alternancia: `pattern:[01]\d|2[0-3]`.

Next, minutes must be from `00` to `59`. In the regular expression language that can be written as `pattern:[0-5]\d`: the first digit `0-5`, and then any digit.
A continuación, los minutos deben estar comprendidos entre `00` y `59`. En el lenguaje de expresiones regulares que se puede escribir como `pattern:[0-5]\d`: el primer dígito `0-5`, y luego culquier otro.

If we glue hours and minutes together, we get the pattern: `pattern:[01]\d|2[0-3]:[0-5]\d`.
Si pegamos minutos y segundos juntos, obtenemos el patrón: `pattern:[01]\d|2[0-3]:[0-5]\d`.

We're almost done, but there's a problem. The alternation `pattern:|` now happens to be between `pattern:[01]\d` and `pattern:2[0-3]:[0-5]\d`.
Ya casi terminamos, pero hay un problema. La alternancia `pattern:|` ahora pasa a estar entre `pattern:[01]\d` y `pattern:2[0-3]:[0-5]\d`.

That is: minutes are added to the second alternation variant, here's a clear picture:
Es decir: se agregan minutos a la segunda variante de alternancia, aquí hay una imagen clara:

```
[01]\d | 2[0-3]:[0-5]\d
```

That pattern looks for `pattern:[01]\d` or `pattern:2[0-3]:[0-5]\d`.
Este patrón busca `pattern:[01]\d` o `pattern:2[0-3]:[0-5]\d`.

But that's wrong, the alternation should only be used in the "hours" part of the regular expression, to allow `pattern:[01]\d` OR `pattern:2[0-3]`. Let's correct that by enclosing "hours" into parentheses: `pattern:([01]\d|2[0-3]):[0-5]\d`.
Pero eso es incorrecto, la alternancia solo debe usarse en la parte "horas" de la expresión regular, para permitir `pattern:[01]\d` O `pattern:2[0-3]`. Corregiremos eso encerrando las "horas" entre paréntesis: `pattern:([01]\d|2[0-3]):[0-5]\d`.

The final solution:
La solución final sería:

```js run
let regexp = /([01]\d|2[0-3]):[0-5]\d/g;
Expand Down