Skip to content

Alternation (OR) | #280

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 1 commit into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all 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 première idée peut être de lister les langages avec des `|` entre deux.

But that doesn't work right:
Mais cela ne fonctionne pas correctement :

```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.
Le moteur d'expression régulière regarde les alternances une par une. C'est-à-dire : il regarde d'abord si nous avons `match:Java`, sinon il recherche `match:JavaScript` et ainsi de suite.

As a result, `match:JavaScript` can never be found, just because `match:Java` is checked first.
Ainsi, `match:JavaScript` ne peut jamais être trouvé, puisque `match:Java` est vérifié en premier.

The same with `match:C` and `match:C++`.
Pareil pour `match:C` et `match:C++`.

There are two solutions for that problem:
Il y a deux solutions à ce problème :

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. Changer l'ordre pour vérifier le mot le plus long en premier : `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Fusionner les mots commençant de la même manière : `pattern:Java(Script)?|C(\+\+)?|PHP`.

In action:
En action :

```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
# Trouver les langages de programmation

There are many programming languages, for instance Java, JavaScript, PHP, C, C++.
Il y a beaucoup de langages de programmation, par exemple Java, JavaScript, PHP, C, C++.

Create a regexp that finds them in the string `subject:Java JavaScript PHP C++ C`:
Créez une regexp qui les trouve dans une chaine de caractère `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)\]`.
Un tag d'ouverture correspond à `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.
Ensuite pour trouver tout jusqu'au tag de fermeture, utilisons le modèle `pattern:.*?` avec le flag `pattern:s` pour trouver n'importe quel caractère en plus des sauts de ligne, puis ajoutons une référence au tag de fermeture.

The full pattern: `pattern:\[(b|url|quote)\].*?\[/\1\]`.
Le modèle : `pattern:\[(b|url|quote)\].*?\[/\1\]`.

In action:
En action :

```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.
Veuillez noter qu'en plus de `pattern:[` et `pattern:]`, nous avons dû échapper un slash pour le tag de fermeture `pattern:[\/\1]` puisque normalement un slash ferme le modèle.
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
# Find bbtag pairs
# Trouver les paires de bbtag

A "bb-tag" looks like `[tag]...[/tag]`, where `tag` is one of: `b`, `url` or `quote`.
Un "bb-tag" ressemble à `[tag]...[/tag]`, `tag` peut être : `b`, `url` ou `quote`.

For instance:
Par exemple :
```
[b]text[/b]
[url]http://google.com[/url]
```

BB-tags can be nested. But a tag can't be nested into itself, for instance:
Les BB-tags peuvent être imbriqués. Mais un tag ne peut pas être imbriqué dans lui même, par exemple :

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

Can't happen:
Ne peut pas arriver:
[b][b]text[/b][/b]
```

Tags can contain line breaks, that's normal:
Les tags peuvent contenir des sauts de ligne, c'est normal :

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

Create a regexp to find all BB-tags with their contents.
Créez une regexp pour trouver tous les BB-tags avec leur contenu.

For instance:
Par exemple :

```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 les tags sont imbriqués, alors nous voulons le tag extérieur (si nous voulons nous pouvons continuer la recherche dans le contenu) :

```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 solution : `pattern:/"(\\.|[^"\\])*"/g`.

Step by step:
Etape par etape :

- 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.
- D'abord nous recherchons une guillemet ouvrante `pattern:"`
- Ensuite si nous avons un antislash `pattern:\\` (puisque c'est un caractère spécial nous devons le doubler, mais dans les faits c'est un unique antislash), alors n'importe quel caractère peut se trouver à sa suite (un point).
- Sinon nous prenons n'importe quel caractère à part une guillemet (cela signifierait la fin de la chaine de caractère) et un antislash (pour empêcher les antislash solitaires, un antislash est seulement utilisé avec un autre symbole après lui): `pattern:[^"\\]`
- ...Et on continue jusqu'à atteindre la guillemet fermante.

In action:
En action :

```js run
let regexp = /"(\\.|[^"\\])*"/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# Find quoted strings
# Trouver les chaines de caractère

Create a regexp to find strings in double quotes `subject:"..."`.
Créer une regexp pour trouver les chaines de caractère entre guillemets doubles `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:\\`.
La chaine de caractère devrait supporter l'échappement, comme les chaines de caractère JavaScript. Par exemple, des guillemets peuvent être insérés comme ceci `subject:\"` une nouvelle ligne comme `subject:\n`, et un antislash comme `subject:\\`.

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

Please note, in particular, that an escaped quote `subject:\"` does not end a string.
Veuillez noter qu'une guillemet échapée `subject:\"` ne termine pas une chaine de caractère.

So we should search from one quote to the other ignoring escaped quotes on the way.
Nous devrions donc chercher une guillemet puis la suivante en ignorant celles échapées.

That's the essential part of the task, otherwise it would be trivial.
C'est la partie essentielle de la tâche, à part cela, cela devrait être simple.

Examples of strings to match:
Exemple de chaine de caractère valides :
```js
.. *!*"test me"*/!* ..
.. *!*"Say \"Hello\"!"*/!* ... (escaped quotes inside)
.. *!*"\\"*/!* .. (double slash inside)
.. *!*"\\ \""*/!* .. (double slash and an escaped quote inside)
.. *!*"test me"*/!* ..
.. *!*"Say \"Hello\"!"*/!* ... (guillemets échapées à l'intérieur)
.. *!*"\\"*/!* .. (double slash à l'intérieur)
.. *!*"\\ \""*/!* .. (double slash et guillemets échapées à l'intérieur)
```

In JavaScript we need to double the slashes to pass them right into the string, like this:
En Javascript nous devons doubler les slash pour les placer dans la chaine de caractère, comme ceci :

```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`.
Le début du modèle est évident: `pattern:<style`.

...But then we can't simply write `pattern:<style.*?>`, because `match:<styler>` would match it.
...Mais nous ne pouvons pas juste écrire `pattern:<style.*?>` puisque `match:<styler>` y correspondrait.

We need either a space after `match:<style` and then optionally something else or the ending `match:>`.
Nous avons besoin soit d'un espace après `match:<style` et après optionellement quelque chose d'autre, ou bien la fin `match:>`.

In the regexp language: `pattern:<style(>|\s.*?>)`.
Dans le langage des regexp : `pattern:<style(>|\s.*?>)`.

In action:
En action :

```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
# Trouver la balise entière

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="...">`.
Écrivez une regexp pour trouver la balise `<style...>`. Il devrait trouver la balise en entier: il pourrait ne pas avoir d'attributs `<style>` ou en avoir plusieurs `<style type="..." id="...">`.

...But the regexp should not match `<styler>`!
...Mais la regexp ne devrait pas trouver `<styler>`!

For instance:
Par exemple:

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

Alternation is the term in regular expression that is actually a simple "OR".
Alternance est le terme d'expression régulière qui représente un "OU".

In a regular expression it is denoted with a vertical line character `pattern:|`.
Dans une expression régulière l'alternance est représentée par une barre verticale `pattern:|`.

For instance, we need to find programming languages: HTML, PHP, Java or JavaScript.
Par exemple, nous souhaitons trouver les langages de programmation suivants: HTML, PHP, Java ou JavaScript.

The corresponding regexp: `pattern:html|php|java(script)?`.
La regexp correspondante : `pattern:html|php|java(script)?`.

A usage example:
Exemple d'utilisation:

```js run
let regexp = /html|php|css|java(script)?/gi;
Expand All @@ -18,50 +18,50 @@ let str = "First HTML appeared, then CSS, then 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`.
Nous avons déjà vu une chose similaire, les crochets. Ils permettent de choisir entre plusieurs caractères, par exemple `pattern:gr[ae]y` correspond à `match:gray` ou `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`.
Les crochets n'autorisent que les caractères ou les classes de caractère. L'alternance permet n'importe quelle expression. Une regexp `pattern:A|B|C` signifie `A`, `B` ou `C`.

For instance:
Par exemple:

- `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` signifie la même chose que `pattern:gr[ae]y`.
- `pattern:gra|ey` signifie `match:gra` ou `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`.
Pour appliquer l'alternance à une partie du modèle nous pouvons l'encadrer entre parenthèses:
- `pattern:I love HTML|CSS` correspond à `match:I love HTML` ou `match:CSS`.
- `pattern:I love (HTML|CSS)` correspond à `match:I love HTML` ou `match:I love CSS`.

## Example: regexp for time
## Exemple: regexp d'un temps

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).
Dans les articles précédents il y avait une tâche qui consistait à construire une regexp pour trouver un temps de la forme `hh:mm`, par exemple `12:00`. Mais un simple modèle `pattern:\d\d:\d\d` est trop vague. Il accepte `25:99` comme temps (puisque "99 minutes" correspond au modèle, mais ce temps est invalide).

How can we make a better pattern?
Comment pouvons-nous créer un meilleur modèle ?

We can use more careful matching. First, the hours:
Nous pouvons utiliser une correspondance plus appropriée. Premièrement, les heures :

- 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 le premier chiffre est `0` ou `1`, alors le prochain chiffre peut être: `pattern:[01]\d`.
- Sinon, si le premier chiffre est `2`, alors le prochain doit être `pattern:[0-3]`.
- (aucun autre premier chiffre est autorisé)

We can write both variants in a regexp using alternation: `pattern:[01]\d|2[0-3]`.
Nous pouvons écrire les deux variantes dans une regexp en utilisant l'alternance: `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.
Ensuite, les minutes doivent être entre `00` et `59`. Dans le langage des expression régulières cela peut être écrit `pattern:[0-5]\d`: le premier chiffre `0-5`, puis n'importe quel chiffre.

If we glue hours and minutes together, we get the pattern: `pattern:[01]\d|2[0-3]:[0-5]\d`.
Si nous rejoignons les heures et les minutes ensemble, nous obtenons le modèle: `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`.
Nous y sommes presque, mais il y a un problème. L'alternance `pattern:|` se trouve désormais entre `pattern:[01]\d` et `pattern:2[0-3]:[0-5]\d`.

That is: minutes are added to the second alternation variant, here's a clear picture:
Cela signifie que les minutes sont incluses dans la seconde variante d'alternance, voici un affichage plus clair:

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

That pattern looks for `pattern:[01]\d` or `pattern:2[0-3]:[0-5]\d`.
Ce modèle recherche `pattern:[01]\d` ou `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`.
Mais c'est incorrect, l'alternance ne devrait être utilisé que pour la partie "heures" de l'expression régulière, pour permettre `pattern:[01]\d` OU `pattern:2[0-3]`. Corrigeons cela en mettant les "heures" entre parenthèses : `pattern:([01]\d|2[0-3]):[0-5]\d`.

The final solution:
La solution finale :

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