Meta-caratteri

La potenza delle espressioni regolari deriva dalla possibilità di inserire criteri alternativi oppure ripetuti. Questi sono codificati nel criterio di ricerca tramite l'uso di meta-caratteri, lettere che non indicano se stesse, ma sono interpretate in modo particolare.

Esistono due differenti set di meta-caratteri: quelli che sono riconosciuti ovunque tranne che all'interno di parentesi quadrate, e quelli che sono riconosciuti all'interno di parentesi quadrate. I meta-caratteri che si usano all'esterno delle parentesi quadrate sono:

\
carattere di escape generico con diversi utilizzi
^
indica l'inizio del testo (o della linea in modalità multi-linea)
$
indica la fine del testo (o della linea in modalità multi-linea)
.
indica qualsiasi carattere tranne "a capo" (per default)
[
carattere di inizio della definizione di classe
]
carattere di fine della definizione di classe
|
inizio di un ramo alternativo
(
inizio di un criterio di riconoscimento parziale
)
fine del criterio di riconoscimento parziale
?
estende il significato di (, oppure 0 o 1 occorrenza, oppure occorrenza minima (vedere ripetizione)
*
0 o più occorrenze
+
1 o più occorrenze
{
inizia l'intervallo minimo/massimo di occorrenze
}
termina l'intervallo minimo/massimo di occorrenze
La parte del criterio che si trova tra parentesi quadrate viene detta "classe di caratteri". In una classe di caratteri i meta-caratteri previsti sono:
\
carattere di escape generico con diversi utilizzi
^
nega la classe, ma solo se posto all'inizio
-
indica un intervallo
]
chiude la classe di caratteri
Le sezioni seguenti descriveranno l'uso di ciascuno dei meta-caratteri.

add a note add a note

User Contributed Notes 6 notes

up
0
fiwswe
4 years ago
".    match any character except newline (by default)"

Here "newline" seems to include both \n (LF) and \r (CR) in PHP 7.4.6. PHP 7.3.18 seems to be more tolerant and only include \n (LF).

Example:

<?php
$s
= "HTTP/1.1 200 OK\r\n";
if (!
preg_match('/^HTTP\/(\d\.\d)\s*(\d+).*\n/', $s, $m))
    echo
"Not matched correctly!\n";
else
    echo
"OK\n";
?>

The ".*" is supposed to match 0-n characters including \r (CR). It does so in PHP 7.3.18 but not in PHP 7.4.6.

Result (PHP 7.3.18):
OK

Result (PHP 7.4.6):
Not matched correctly!

A pattern that works in both versions of PHP looks like this:
'/^HTTP\/(\d\.\d)\s*(\d+).*\r?\n/'
up
-1
Kurt Wei
8 years ago
disturbing usage of "any character" for multi-lines...

remark:
'.' (all characters) just does NOT include on single character the newline (\n) by default,
while \n is included in all other matching searches (e.g. \s).
Funny enough, the "carriage return" (\r) is included, when using '.'

You have to write "(.|\\n)" instead of a single dot, with disadvantages in using complex matching-results,

or simple use the "s" modificator to bring dot to accept the newline.

$subject="<tag>Hello\nWorld</tag>";

preg_match( '/<tag>[A-Za-z\\s]*<\\/tag>/' , $subject ); //true
preg_match( '/<tag>[^<]*<\\/tag>/' , $subject ); //true
preg_match( '/<tag>(.|\\n)*<\\/tag>/' , $subject ); //true
preg_match( '/<tag>.*<\\/tag>/s' , $subject ); //true
preg_match( '/<tag>.*<\\/tag>/' , $subject ); //ATTENTION! *false*
up
-1
Wirek
6 years ago
Significantly updated version (with $pat4 and the best $pat5!):
A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
//          C          3                   p          0                   _
$pat1='/\w$/mi';
$pat2='/\w\r?$/mi';
$pat3='/\w\R?$/mi';
$pat4='/\w\v?$/mi';
$pat5='/(*ANYCRLF)\w$/mi';
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
echo
$str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
    .
"\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
    .
"\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
    .
"\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
    .
"\n5 !!! $pat5 ($s): ".print_r($m5[0], true);
// Note the difference between the three very helpful escape sequences in $pat2 (\r), $pat3 (\R), $pat4 (\v) and altered newline option in $pat5 ((*ANYCRLF)) - for some applications at least.

/* The code above results in the following output:
ABC ABC

123 123
def def
nop nop
890 890
QRS QRS

~-_ ~-_
1 !!! /\w$/mi (3): Array
(
    [0] => C
    [1] => 0
    [2] => _
)

2 !!! /\w\r?$/mi (5): Array
(
    [0] => C
    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)

3 !!! /\w\R?$/mi (5): Array
(
    [0] => C

    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)

4 !!! /\w\v?$/mi (5): Array
(
    [0] => C

    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)

5 !!! /(*ANYCRLF)\w$/mi (7): Array
(
    [0] => C
    [1] => 3
    [2] => f
    [3] => p
    [4] => 0
    [5] => S
    [6] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
up
-2
Wirek
6 years ago
An important addendum (with new $pat3_2 utilising \R properly, its results and comments):
Note that there are (sometimes difficult to grasp at first glance) nuances of meaning and application of escape sequences like \r, \R and \v - none of them is perfect in all situations, but they are quite useful nevertheless. Some official PCRE control options and their changes come in handy too - unfortunately neither (*ANYCRLF), (*ANY) nor (*CRLF) is documented here on php.net at the moment (although they seem to be available for over 10 years and 5 months now), but they are described on Wikipedia ("Newline/linebreak options" at https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) and official PCRE library site ("Newline convention" at http://www.pcre.org/original/doc/html/pcresyntax.html#SEC17) pretty well. The functionality of \R appears somehow disappointing (with default configuration of compile time option) according to php.net as well as official description ("Newline sequences" at https://www.pcre.org/original/doc/html/pcrepattern.html#newlineseq) when used improperly.

A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end (or at the beginning) of any line even without the multiple lines mode (/m) or meta-character assertions ($ or ^).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?) of default configuration option for meta-character assertions (^ and $) at compile time of PCRE.
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
//          C          3                   p          0                   _
$pat3='/\w\R?$/mi';    // Somehow disappointing according to php.net and pcre.org when used improperly
$pat3_2='/\w(?=\R)/i';    // Much better with allowed lookahead assertion (just to detect without capture) without multiline (/m) mode; note that with alternative for end of string ((?=\R|$)) it would grab all 7 elements as expected, but '/(*ANYCRLF)\w$/mi' is more straightforward in use anyway
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat3_2, $str, $m4);
echo
$str."\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
    .
"\n3_2 !!! $pat3_2 ($r): ".print_r($m4[0], true);
// Note the difference between the two very helpful escape sequences in $pat3 and $pat3_2 (\R) - for some applications at least.

/* The code above results in the following output:
ABC ABC

123 123
def def
nop nop
890 890
QRS QRS

~-_ ~-_
3 !!! /\w\R?$/mi (5): Array
(
    [0] => C

    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)

3_2 !!! /\w(?=\R)/i (6): Array
(
    [0] => C
    [1] => 3
    [2] => f
    [3] => p
    [4] => 0
    [5] => S
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
up
-2
Wirek
6 years ago
A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
//          C          3                   p          0                   _
$pat1='/\w$/mi';
$pat2='/\w\r?$/mi';
$pat3='/\w\R?$/mi';
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
echo
$str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
    .
"\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
    .
"\n3 !!! $pat3 ($p): ".print_r($m3[0], true);
// Note the difference between the two very helpful escape sequences in $pat2 (\r) and in $pat3 (\R) - for some applications at least.

/* The code above results in the following output:
ABC ABC

123 123
def def
nop nop
890 890
QRS QRS

~-_ ~-_
1 !!! /\w$/mi (3): Array
(
    [0] => C
    [1] => 0
    [2] => _
)

2 !!! /\w\r?$/mi (5): Array
(
    [0] => C
    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)

3 !!! /\w\R?$/mi (5): Array
(
    [0] => C

    [1] => 3
    [2] => p
    [3] => 0
    [4] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
up
-37
Thomas
9 years ago
The meta character $ accepts a (one) newline character (\n).

(Take a moment to let this information sink in)

You might want to (r)trim() your input afterwards if you have a match because otherwise it (still) might not meet a length requirement or other strange stuff might happen when you store the input as-is.
To Top