Skip to content

Alternation (OR) | #323

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 5 commits into from
Jun 20, 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 prima idea potrebbe essere elencare i linguaggi separati da `|`.

But that doesn't work right:
Ma non funziona bene:

```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.
L'interprete dell'espressione regolare cerca le alternanze una per una. In altre parole: per prima cosa cerca `match:Java`, se non la trova cerca `match:JavaScript` e così via.

As a result, `match:JavaScript` can never be found, just because `match:Java` is checked first.
Il risultato è che `match:JavaScript` non trova mai corrispondenza proprio perché `match:Java` viene controllato per prima.

The same with `match:C` and `match:C++`.
Lo stesso accade con `match:C` e `match:C++`.

There are two solutions for that problem:
Ci sono due soluzioni per questo 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. Cambiare l'ordine di verifica mettendo per primo il termine più lungo: `pattern:JavaScript|Java|C\+\+|C|PHP`.
2. Unire le varianti che cominciano allo stesso modo: `pattern:Java(Script)?|C(\+\+)?|PHP`.

In action:
In azione:

```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
# Trovate il nome dei linguaggi di programmazione

There are many programming languages, for instance Java, JavaScript, PHP, C, C++.
Ci sono molti linguaggi di programmazione, Per esempio Java, JavaScript, PHP, C, C++.

Create a regexp that finds them in the string `subject:Java JavaScript PHP C++ C`:
Create una regexp che li trovi nella stringa `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)\]`.
Il tag di apertura è `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.
Successivamente per trovare tutto fino al tag di chiusura usiamo il pattern `pattern:.*?` con il flag `pattern:s` per cercare la corrispondenza con ogni carattere inclusa una nuova riga. Per concludere aggiungiamo un riferimento all'indietro per il tag di chiusura.

The full pattern: `pattern:\[(b|url|quote)\].*?\[/\1\]`.
L'intero pattern risultante è: `pattern:\[(b|url|quote)\].*?\[/\1\]`.

In action:
In azione:

```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.
Si noti che oltre l'escape di `pattern:[` e `pattern:]`, abbiamo dovuto fare l'escape dello slash del tag di chiusura `pattern:[\/\1]`, poiché normalmente lo slash termina il pattern.
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
# Find bbtag pairs
# Trovate le coppie di bbtag

A "bb-tag" looks like `[tag]...[/tag]`, where `tag` is one of: `b`, `url` or `quote`.
Un "bb-tag" si presenta così `[tag]...[/tag]`, in cui `tag` è uno tra: `b`, `url` o `quote`.

For instance:
Ad esempio:
```
[b]text[/b]
[url]http://google.com[/url]
```

BB-tags can be nested. But a tag can't be nested into itself, for instance:
I BB-tags possono essere annidati. Un tag, tuttavia, non può essere contenuto all'interno di uno dello stesso tipo, ad esempio:

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

Can't happen:
Non deve verificarsi:
[b][b]text[/b][/b]
```

Tags can contain line breaks, that's normal:
I tag possono contenere interruzioni di linea, questo è del tutto normale:

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

Create a regexp to find all BB-tags with their contents.
Create una regexp per trovare tutti i BB-tags con il loro contenuto.

For instance:
Per esempio:

```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):
In caso di tag annidati ci occorre il tag esterno (se lo desideriamo possiamo continuare la ricerca nel contenuto appena ricavato):

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

Step by step:
Passo dopo passo:

- First we look for an opening quote `pattern:"`
- Then if we have a backslash `pattern:\\` (we have to double it in the pattern because it is a special character), 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.
- Innanzitutto cerchiamo un doppio apice di apertura `pattern:"`
- Quindi se abbiamo un backslash `pattern:\\` (dobbiamo raddoppiarlo nel pattern perché è un carattere speciale), qualsiasi carattere dopo di esso è consentito (il punto).
- Altrimenti consideriamo ogni carattere eccetto un doppio apice (che significherebbe la fine della stringa) ed un backslash (per evitare backslashe isolati, il backslash è usato soltanto in congiunzione con altri simboli dopo di esso): `pattern:[^"\\]`
- ...e così via fino al doppio apice di chiusura.

In action:
In azione:

```js run
let regexp = /"(\\.|[^"\\])*"/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# Find quoted strings
# Trovate le stringhe tra doppi apici

Create a regexp to find strings in double quotes `subject:"..."`.
Create una regexp per trovare le stringhe tra doppi apici `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:\\`.
Le stringhe dovrebbero supportare l'escape allo stesso modo delle stringhe JavaScript. Per esempio, i doppi apici possono essere inseriti come `subject:\"` una nuova linea come `subject:\n`, e lo stesso slash come `subject:\\`.

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

Please note, in particular, that an escaped quote `subject:\"` does not end a string.
Si noti che, in particolare, un doppio apice con escape `subject:\"` non termina una stringa.

So we should search from one quote to the other ignoring escaped quotes on the way.
Noi dovremmo cercare, pertanto, da un doppio apice fino all'altro ignorando quelli con escape tra i due.

That's the essential part of the task, otherwise it would be trivial.
Questo è la parte fondamentale dell'esercitazione, altrimenti diventerebbe banale.

Examples of strings to match:
Ecco degli esempi di stringhe che corrispondono:
```js
.. *!*"test me"*/!* ..
.. *!*"Say \"Hello\"!"*/!* ... (escaped quotes inside)
.. *!*"\\"*/!* .. (double slash inside)
.. *!*"\\ \""*/!* .. (double slash and an escaped quote inside)
.. *!*"Say \"Hello\"!"*/!* ... (contiene doppi apici con escape)
.. *!*"\\"*/!* .. (contiene un doppio slash)
.. *!*"\\ \""*/!* .. (contiene un doppio slash e un doppio apice con escape)
```

In JavaScript we need to double the slashes to pass them right into the string, like this:
In JavaScript abbiamo bisogno di raddoppiare lo slash per passarli correttamente all'interno della stringa, in questo modo:

```js run
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';

// the in-memory string
// la stringa in memoria
alert(str); // .. "test me" .. "Say \"Hello\"!" .. "\\ \"" ..
```
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

The pattern start is obvious: `pattern:<style`.
L'inizio del pattern è ovvio: `pattern:<style`.

...But then we can't simply write `pattern:<style.*?>`, because `match:<styler>` would match it.
Ma successivamente non possiamo semplicemente scrivere `pattern:<style.*?>`, poiché altrimenti `match:<styler>` troverebbe corrispondenza.

We need either a space after `match:<style` and then optionally something else or the ending `match:>`.
Abbiamo bisogno di uno spazio dopo `match:<style` e dopo facoltativamente qualcos'altro o la `match:>` finale.

In the regexp language: `pattern:<style(>|\s.*?>)`.
Tradotto nel linguaggio delle regexp: `pattern:<style(>|\s.*?>)`.

In action:
In azione:

```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
# Trovate l'intero tag

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="...">`.
Scrivete una regexp per trovare il tag `<style...>`. Essa dovrebbe trovare corrispondenza con l'intero tag: esso potrebbe non avere alcun attributo `<style>` o averne diversi `<style type="..." id="...">`.

...But the regexp should not match `<styler>`!
La regexp, tuttavia, non dobrebbe accettare `<styler>`!

For instance:
Per esempio:

```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) |
# Alternanza (OR) |

Alternation is the term in regular expression that is actually a simple "OR".
Alternanza è un termine usato nelle espressioni regolari che, in realtà, consiste in un semplice "OR".

In a regular expression it is denoted with a vertical line character `pattern:|`.
È indicata con un carattere di linea verticale `pattern:|`.

For instance, we need to find programming languages: HTML, PHP, Java or JavaScript.
Supponiamo di aver bisogno di trovare il nome di un linguaggio di programmazione: HTML, PHP, Java o JavaScript.

The corresponding regexp: `pattern:html|php|java(script)?`.
Ecco la regexp corrispondente: `pattern:html|php|java(script)?`.

A usage example:
Ed ora un esempio d'uso:

```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`.
Abbiamo già incontrato una funzionalità simile: le parentesi quadre. Essi permettono di scegliere tra più caratteri, ad esempio `pattern:gr[ae]y` trova corrispondenza 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`.
Le parentesi quadre consentono solo caratteri o classi di caratteri. L'alternanza consente qualsiasi espressione. Una regexp `pattern:A|B|C` significa una delle espressioni `A`, `B` o `C`.

For instance:
Per esempio:

- `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` ha lo stesso identico significato di `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`.
Per applicare l'alternanza ad una determinata parte di un pattern, dobbiamo racchiuderla tra parentesi:
- `pattern:I love HTML|CSS` trova `match:I love HTML` o `match:CSS`.
- `pattern:I love (HTML|CSS)` corrisponde a `match:I love HTML` o `match:I love CSS`.

## Example: regexp for time
## Esempio: regexp per un orario

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).
Negli articoli precedenti abbiamo effettuato un'esercitazione per realizzare una regexp e trovare un orario nel formato `hh:mm`, ad esempio `12:00`. Un semplice `pattern:\d\d:\d\d`, tuttavia, è troppo impreciso. Accetta un orario come `25:99` (poiché 99 minuti trova corrispondenza nel pattern, ma non è un orario valido).

How can we make a better pattern?
Come possiamo migliorare questo pattern?

We can use more careful matching. First, the hours:
Possiamo cercare una corrispondenza più accurata. Per prima cosa, le ore:

- 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)
- Se la prima cifra è `0` o `1`, allora la cifra successiva può essere una qualsiasi: `pattern:[01]\d`.
- Diversamente, se la prima cifra è `2`, la successiva deve essere `pattern:[0-3]`.
- Non può esserci un altro carattere come prima cifra.

We can write both variants in a regexp using alternation: `pattern:[01]\d|2[0-3]`.
Possiamo scrivere entrambe le varianti in una regexp usando l'alternanza: `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.
I minuti a seguire, essi devono essere compresi in un intervallo tra `00` e `59`. In un'espressione regolare ciò può essere reso come `pattern:[0-5]\d`: la prima cifra `0-5`, quindi un numero qualsiasi.

If we glue hours and minutes together, we get the pattern: `pattern:[01]\d|2[0-3]:[0-5]\d`.
Unendo le ore con i minuti otteniamo il pattern seguente: `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`.
Abbiamo quasi finito, ma c'è ancora un problema. L'alternanza `pattern:|` al momento sembra avvenire tra `pattern:[01]\d` e `pattern:2[0-3]:[0-5]\d`.

That is: minutes are added to the second alternation variant, here's a clear picture:
In altre parole: i minuti sono aggiunti al secondo termine dell'alternanza, ecco una rappresentazione più chiara:

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

That pattern looks for `pattern:[01]\d` or `pattern:2[0-3]:[0-5]\d`.
Questo pattern cerca `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`.
Non è quello che vogliamo, l'alternanza dovrebbe riguardare solo le ore e consentire `pattern:[01]\d` o `pattern:2[0-3]`. Correggiamo racchiudendo le ore tra parentesi: `pattern:([01]\d|2[0-3]):[0-5]\d`.

The final solution:
Ed ecco la soluzione definitiva:

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