Skip to content

Lookahead and lookbehind #324

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 7 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,9 +1,9 @@

The regexp for an integer number is `pattern:\d+`.
La regexp per un numero intero è `pattern:\d+`.

We can exclude negatives by prepending it with the negative lookbehind: `pattern:(?<!-)\d+`.
Possiamo escludere i numeri negativi anteponendo il segno meno con il lookbehind: `pattern:(?<!-)\d+`.

Although, if we try it now, we may notice one more "extra" result:
Anche se, nel caso in cui lo provassimo ora, potremmo notare un altro risultato inatteso:

```js run
let regexp = /(?<!-)\d+/g;
Expand All @@ -13,11 +13,11 @@ let str = "0 12 -5 123 -18";
console.log( str.match(regexp) ); // 0, 12, 123, *!*8*/!*
```

As you can see, it matches `match:8`, from `subject:-18`. To exclude it, we need to ensure that the regexp starts matching a number not from the middle of another (non-matching) number.
Come potete osservare trova `match:8` da `subject:-18`. Per escluderlo, dobbiamo assicurarci che la regexp non cominci a cercare una corrispondenza di un numero dalla metà di un altro numero non corrispondente.

We can do it by specifying another negative lookbehind: `pattern:(?<!-)(?<!\d)\d+`. Now `pattern:(?<!\d)` ensures that a match does not start after another digit, just what we need.
Possiamo farlo specificando un altro lookbehind negativo: `pattern:(?<!-)(?<!\d)\d+`. Ora `pattern:(?<!\d)` assicura che la corrispondenza non cominci dopo un altro numero, proprio quello che volevamo.

We can also join them into a single lookbehind here:
Potremmo anche unire il tutto in un singolo lookbehind in questo modo:

```js run
let regexp = /(?<![-\d])\d+/g;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Find non-negative integers
# Trovate gli interi non negativi

There's a string of integer numbers.
Data una stringa di numeri interi, create una regexp che cerchi solo quelli non negativi (lo zero è consentito).

Create a regexp that looks for only non-negative ones (zero is allowed).

An example of use:
Un esempio d'uso:
```js
let regexp = /your regexp/g;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
In order to insert after the `<body>` tag, we must first find it. We can use the regular expression pattern `pattern:<body.*?>` for that.
Per inserire qualcosa dopo il tag `<body>` dobbiamo prima trovarlo. A questo scopo possiamo usare l'espressione regolare `pattern:<body.*?>`.

In this task we don't need to modify the `<body>` tag. We only need to add the text after it.
In questa esercitazione non abbiamo bisogno di modificare il tag `<body>`. Dobbiamo solo aggiungere del testo dopo di esso.

Here's how we can do it:
Ecco come possiamo farlo:

```js run
let str = '...<body style="...">...';
Expand All @@ -11,9 +11,9 @@ str = str.replace(/<body.*?>/, '$&<h1>Hello</h1>');
alert(str); // ...<body style="..."><h1>Hello</h1>...
```

In the replacement string `$&` means the match itself, that is, the part of the source text that corresponds to `pattern:<body.*?>`. It gets replaced by itself plus `<h1>Hello</h1>`.
Nella stringa di sostituzione `$&` identifica la stessa corrispondenza, in altre parole, la parte della stringa sorgente che trova riscontro con `pattern:<body.*?>`. Essa viene sostituita da se stessa più l'aggiunta di `<h1>Hello</h1>`.

An alternative is to use lookbehind:
L'uso del lookbehind costituisce un'alternativa:

```js run
let str = '...<body style="...">...';
Expand All @@ -22,15 +22,15 @@ str = str.replace(/(?<=<body.*?>)/, `<h1>Hello</h1>`);
alert(str); // ...<body style="..."><h1>Hello</h1>...
```

As you can see, there's only lookbehind part in this regexp.
Come potete osservare, c'è solo la parte di lookbehind in questa regexp.

It works like this:
- At every position in the text.
- Check if it's preceeded by `pattern:<body.*?>`.
- If it's so then we have the match.
Funziona in questo modo:
- Per ogni posizione nella stringa.
- Verifica se è preceduta da `pattern:<body.*?>`.
- In caso affermativo abbiamo trovato la corrispondenza.

The tag `pattern:<body.*?>` won't be returned. The result of this regexp is literally an empty string, but it matches only at positions preceeded by `pattern:<body.*?>`.
Il tag `pattern:<body.*?>` non verrà restituito. Il risultato di questa regexp è letteralmente una stringa vuota, ma individua le posizioni precedute da `pattern:<body.*?>`.

So it replaces the "empty line", preceeded by `pattern:<body.*?>`, with `<h1>Hello</h1>`. That's the insertion after `<body>`.
Quindi sostituisce uno "spazio vuoto" preceduto da `pattern:<body.*?>`, con `<h1>Hello</h1>`. In altre parole effettua un inserimento dopo `<body>`.

P.S. Regexp flags, such as `pattern:s` and `pattern:i` can also be useful: `pattern:/<body.*?>/si`. The `pattern:s` flag makes the dot `pattern:.` match a newline character, and `pattern:i` flag makes `pattern:<body>` also match `match:<BODY>` case-insensitively.
P.S. I flag `pattern:s` e `pattern:i` potrebbero inoltre risultare utili: `pattern:/<body.*?>/si`. Il flag `pattern:s` fa in modo che il `pattern:.` identifichi anche un carattere di nuova riga, e con il flag `pattern:i` otteniamo che `pattern:<body>` e `match:<BODY>` costituiscano entrambi un riscontro.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Insert After Head
# Inserimento dopo la sezione head

We have a string with an HTML Document.
Abbiamo una stringa e un documento HTML.

Write a regular expression that inserts `<h1>Hello</h1>` immediately after `<body>` tag. The tag may have attributes.
Scrivete un'espressione regolare che inserisca `<h1>Hello</h1>` subito dopo il tag `<body>`. Il tag può avere degli attributi.

For instance:
Per esempio:

```js
let regexp = /your regular expression/;
Expand All @@ -20,7 +20,7 @@ let str = `
str = str.replace(regexp, `<h1>Hello</h1>`);
```

After that the value of `str` should be:
Dopo l'inserimento il valore di `str` dovrebbe essere:
```html
<html>
<body style="height: 200px"><h1>Hello</h1>
Expand Down
102 changes: 51 additions & 51 deletions 9-regular-expressions/14-regexp-lookahead-lookbehind/article.md
Original file line number Diff line number Diff line change
@@ -1,107 +1,107 @@
# Lookahead and lookbehind
# Lookahead e lookbehind

Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern.
Talvolta abbiamo bisogno di trovare soltanto quei riscontri per un pattern che sono seguiti o preceduti da un altro pattern.

There's a special syntax for that, called "lookahead" and "lookbehind", together referred to as "lookaround".
Esiste a questo scopo una sintassi speciale denominata "lookahead" e "lookbehind", indicata complessivamente con il termine "lookaround".

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.
Per cominciare troviamo il prezzo in una stringa come `subject:1 turkey costs 30€`. In parole semplici: un numero seguito dal simbolo di valuta `subject:€`.

## Lookahead

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`.
La sintassi è: `pattern:X(?=Y)`, che significa "cerca `pattern:X`, ma trova la corrispondenza solo se seguita da `pattern:Y`". Possiamo sostituire `pattern:X` e `pattern:Y` con un pattern qualsiasi.

For an integer number followed by `subject:€`, the regexp will be `pattern:\d+(?=€)`:
Per un numero intero seguito da `subject:€`, la regexp sarà `pattern:\d+(?=€)`:

```js run
let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=€)/) ); // 30, the number 1 is ignored, as it's not followed by
alert( str.match(/\d+(?=€)/) ); // 30, viene ignorato il numero 1 in quanto non seguito da
```

Please note: the lookahead is merely a test, the contents of the parentheses `pattern:(?=...)` is not included in the result `match:30`.
Si noti che la parte lookahead è solo un test e pertanto il contenuto tra parentesi `pattern:(?=...)` non è incluso nel risultato `match:30`.

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.
Quando cerchiamo `pattern:X(?=Y)` l'interprete dell'espressione regolare trova `pattern:X` e successivamente verifica anche la presenza di `pattern:Y` subito dopo di esso. In caso contrario la corrispondenza potenziale viene scartata e la ricerca prosegue.

More complex tests are possible, e.g. `pattern:X(?=Y)(?=Z)` means:
Sono possibili test più complessi, ad esempio `pattern:X(?=Y)(?=Z)` significa:

1. Find `pattern:X`.
2. Check if `pattern:Y` is immediately after `pattern:X` (skip if isn't).
3. Check if `pattern:Z` is also immediately after `pattern:X` (skip if isn't).
4. If both tests passed, then the `pattern:X` is a match, otherwise continue searching.
1. Trova `pattern:X`.
2. Verifica se `pattern:Y` sia subito dopo `pattern:X` (non proseguire in caso contrario).
3. Verifica se `pattern:Z` sia anch'esso dopo `pattern:X` (non proseguire in caso contrario).
4. Se entrambi i test trovano riscontro considera `pattern:X` una corrispondenza, diversamente continua la ricerca.

In other words, such pattern means that we're looking for `pattern:X` followed by `pattern:Y` and `pattern:Z` at the same time.
In altre parole, questo pattern significa che stiamo cercando `pattern:X` seguito sia da `pattern:Y` sia da `pattern:Z`.

That's only possible if patterns `pattern:Y` and `pattern:Z` aren't mutually exclusive.
Il che è possibile solo se i pattern `pattern:Y` e `pattern:Z` non si escludono a vicenda.

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)`:
Per esempio, `pattern:\d+(?=\s)(?=.*30)` cerca `pattern:\d+` seguito da uno spazio `pattern:(?=\s)`, e poi c'è `30` da qualche parte dopo di esso `pattern:(?=.*30)`:

```js run
let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1
```

In our string that exactly matches the number `1`.
Nella nostra stringa trova esatta corrispondenza nel numero `1`.

## Negative lookahead
## Lookahead negativo

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:€`.
Supponiamo invece di volere nella stessa stringa solo la quantità, non il prezzo. Quindi il numero `pattern:\d+`, NON seguito da `subject:€`.

For that, a negative lookahead can be applied.
A questo scopo può essere applicato un lookahead negativo.

The syntax is: `pattern:X(?!Y)`, it means "search `pattern:X`, but only if not followed by `pattern:Y`".
La sintassi è: `pattern:X(?!Y)`, significa "cerca `pattern:X`, ma solo se non seguito da `pattern:Y`".

```js run
let str = "2 turkeys cost 60€";

alert( str.match(/\d+\b(?!€)/g) ); // 2 (the price is not matched)
alert( str.match(/\d+\b(?!€)/g) ); // 2 (il prezzo non costituisce corrispondenza)
```

## Lookbehind

Lookahead allows to add a condition for "what follows".
Lookahead permette di porre una condizione per "quello che segue".

Lookbehind is similar, but it looks behind. That is, it allows to match a pattern only if there's something before it.
Lookbehind è simile, ma cerca quello che precede. Consente quindi di trovare una corrispondenza per un pattern solo se c'è qualcosa prima di esso.

The syntax is:
- Positive lookbehind: `pattern:(?<=Y)X`, matches `pattern:X`, but only if there's `pattern:Y` before it.
- Negative lookbehind: `pattern:(?<!Y)X`, matches `pattern:X`, but only if there's no `pattern:Y` before it.
La sintassi è:
- Lookbehind positivo: `pattern:(?<=Y)X`, trova `pattern:X`, ma solo se c'è `pattern:Y` prima di esso.
- Lookbehind negativo: `pattern:(?<!Y)X`, trova `pattern:X`, ma solo se non c'è alcun `pattern:Y` prima di esso.

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:$`:
Cambiamo, ad esempio, il prezzo in dollari USA. Il segno del dollaro è posto di solito prima del numero, per cercare pertanto `$30` useremo `pattern:(?<=\$)\d+` un importo preceduto da `subject:$`:

```js run
let str = "1 turkey costs $30";

// the dollar sign is escaped \$
alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number)
// facciamo l'escape al segno del dollaro \$
alert( str.match(/(?<=\$)\d+/) ); // 30 (salta il numero senza segno di valuta)
```

And, if we need the quantity -- a number, not preceded by `subject:$`, then we can use a negative lookbehind `pattern:(?<!\$)\d+`:
Se abbiamo bisogno della quantità, il numero, non preceduto da `subject:$`, allora possiamo usare il lookbehind negativo `pattern:(?<!\$)\d+`:

```js run
let str = "2 turkeys cost $60";

alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (the price is not matched)
alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (il risultato non include il prezzo)
```

## Capturing groups
## Gruppi di acquisizione

Generally, the contents inside lookaround parentheses does not become a part of the result.
Generalmente il contenuto dentro le parentesi di lookaround non diventa parte del risultato.

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:€`.
Nel pattern `pattern:\d+(?=€)`, ad esempio, il segno `pattern:€` non viene acquisito nella corrispondenza. È del tutto normale: stiamo cercando il numero `pattern:\d+`, mentre `pattern:(?=€)` è solo un test che indica che il numero dovrebbe essere seguito da `subject:€`.

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.
In alcune situazioni, tuttavia, potremmo voler catturare anche l'espressione del lookaround, o una parte di essa. Questo è possibile: è sufficiente racchiudere la parte desiderata all'interno di parentesi aggiuntive.

In the example below the currency sign `pattern:(€|kr)` is captured, along with the amount:
Nell'esempio sotto, il segno di valuta `pattern:(€|kr)` viene acquisito insieme all'importo:

```js run
let str = "1 turkey costs 30€";
let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr
let regexp = /\d+(?=(€|kr))/; // parentesi addizionali intorno €|kr

alert( str.match(regexp) ); // 30, €
```

And here's the same for lookbehind:
Stesso discorso per il lookbehind:

```js run
let str = "1 turkey costs $30";
Expand All @@ -110,21 +110,21 @@ let regexp = /(?<=(\$|£))\d+/;
alert( str.match(regexp) ); // 30, $
```

## Summary
## Riepilogo

Lookahead and lookbehind (commonly referred to as "lookaround") are useful when we'd like to match something depending on the context before/after it.
Il lookahead e il lookbehind (comunemente denominati con il termine "lookaround") sono utili quando vogliamo trovare qualcosa in base a ciò viene prima o dopo di esso.

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.
Nel caso di espressioni regolari semplici potremmo ottenere lo stesso risultato manualmente. In altre parole: troviamo ogni riscontro, e quindi filtriamo i risultati in base alla posizione nel ciclo iterativo.

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.
Ricordiamoci che `str.match` (senza il flag `pattern:g`) e `str.matchAll` (sempre) restituiscono i risultati in un array con la proprietà `index`, conosciamo pertanto l'esatta posizione della corrispondenza e possiamo stabilirne il contesto.

But generally lookaround is more convenient.
Generalmente, però, il lookaround è più efficiente.

Lookaround types:
Tipi di lookaround:

| Pattern | type | matches |
| Pattern | Tipo | Riscontri |
|--------------------|------------------|---------|
| `X(?=Y)` | Positive lookahead | `pattern:X` if followed by `pattern:Y` |
| `X(?!Y)` | Negative lookahead | `pattern:X` if not followed by `pattern:Y` |
| `(?<=Y)X` | Positive lookbehind | `pattern:X` if after `pattern:Y` |
| `(?<!Y)X` | Negative lookbehind | `pattern:X` if not after `pattern:Y` |
| `X(?=Y)` | Lookahead positivo | `pattern:X` se seguito da `pattern:Y` |
| `X(?!Y)` | Lookahead negativo | `pattern:X` se seguito da `pattern:Y` |
| `(?<=Y)X` | Lookbehind positivo | `pattern:X` se dopo `pattern:Y` |
| `(?<!Y)X` | Lookbehind negativo | `pattern:X` se dopo `pattern:Y` |
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy