"line break" is ill-defined:
-- Windows uses CR+LF (\r\n)
-- Linux LF (\n)
-- OSX CR (\r)
Little-known special character:
\R in preg_* matches all three.
preg_match( '/^\R$/', "match\nany\\n\rline\r\nending\r" ); // match any line endings
Le caractère antislash a de nombreuses utilisations. En premier lieu, s'il est suivi d'un caractère non alphanumérique, il ne prendra pas la signification spéciale qui y est rattachée. Cette utilisation de l'antislash comme caractère de protection s'applique à l'intérieur et à l'extérieur des classes de caractères.
Par exemple, pour rechercher le
caractère étoile "*
", il faut
écrire dans le masque : "\*
". Cela
s'applique dans tous les cas, que le caractère qui suive
soit un métacaractère ou non. C'est un moyen sûr
pour s'assurer qu'un caractère sera recherché
pour sa valeur littérale, plutôt que pour sa valeur
spéciale. En particulier, pour rechercher les antislashs,
il faut écrire : "\\
".
Note:
La chaîne de caractères PHP simple ou double guillemet a une signification spéciale des antislashs. Donc, si \ doit être recherché avec une expression rationnelle \\, alors "\\\\" ou '\\\\' doit être utilisé dans le code PHP.
Si un masque est utilisé avec l'option
PCRE_EXTENDED,
les espaces blancs du masque, mais qui ne sont pas dans une
classe de caractères et les caractères entre dièse
"#
", ainsi que les nouvelles lignes sont ignorées.
L'antislash peut être utilisé pour les protéger et ainsi
rechercher un espace ou un dièse.
La deuxième utilité de l'antislash est de pouvoir coder des caractères invisibles dans les masques. Il n'y a pas de restriction sur la place de ces caractères invisibles, hormis pour le caractère nul qui doit terminer le masque. Lors de la préparation du masque, il est souvent plus pratique d'utiliser les séquences d'échappement suivantes, plutôt que le caractère binaire qu'elles représentent :
Dans la séquence "\cx
" si "x
"
est en minuscule, il est converti en majuscule. Puis, le bit 6 (hex 40)
est inversé. Ainsi "\cz
" devient hex 1A,
mais "\c{
" devient hex 3B, tandis que "\c;
"
devient hex 7B.
Après "\x
", deux caractères
hexadécimaux sont lus (les lettres peuvent être en majuscule
ou minuscule).
En mode UTF-8, "\x{...}
"
est autorisée, où le contenu des accolades est une chaîne hexadécimale.
Il sera interprété comme un caractère UTF-8 où le numéro de code est
le numéro hexadécimal donné. La séquence d'échappement hexadécimale
originale, \xhh
, correspond à un caractère UTF-8
sur 2 octets si la valeur est plus grande que 127.
Après "\0
", deux caractères octaux sont lus.
Dans chacun des cas, le métacaractère tente de lire autant
de caractères que possible. Ainsi, la séquence
"\0\x\07
" sera comprise comme deux caractères nuls,
suivis d'un caractère alarme (BEL). Assurez-vous que vous fournissez
suffisamment de chiffres après le métacaractère.
L'antislash de fin suivi par un nombre autre que 0 est compliqué. À l'extérieur d'une classe de caractère, PCRE le lit, et tous les nombres qui suivent, en tant que nombres décimaux. Si le nombre est plus petit que 10 ou s'il y a eu au moins précédemment une parenthèse gauche capturante dans l'expression, la séquence entière est prise en tant que référence arrière. Une description sur le fonctionnement est donnée plus tard, suivez la discussion sur les parenthèses des sous masques.
À l'intérieur d'un caractère de classe ou s'il est plus grand que 9, et qu'il n'y a pas eu assez de parenthèses ouvrantes auparavant, PCRE lit jusqu'à 3 chiffres octaux à la suite de l'antislash, et génère un octet unique, à partir des 8 bits de poids faible de la séquence. Tous les chiffres qui suivent ne sont pas interprétés, et se représentent eux-mêmes. Par exemple:
Les valeurs octales supérieures ou égales à 100 ne doivent pas être introduites par un 0, car seuls les trois premiers octets seront lus.
Toutes les séquences qui définissent une valeur d'un seul
octet peuvent être utilisées dans les classes de caractères,
et à l'extérieur. De plus, dans une classe de caractères,
la séquence "\b
" est interprétée
comme un caractère effacer (hex 08). À l'extérieur,
elle peut avoir d'autres significations
(voir ci-dessous).
On peut encore se servir de l'antislash pour préciser des types génériques de valeurs :
Chaque paire précédente définit une partition de la table des caractères : les deux ensembles sont disjoints. Un caractère satisfera soit un métacaractère, soit l'autre.
Les caractères "blancs" sont HT (9), LF (10), FF (12), CR (13), et espace (32). Cependant, lors de l'utilisation d'une locale particulière, tous les caractères se trouvant dans l'intervalle 128-255 peuvent aussi être considérés comme caractère blanc, par exemple NBSP (A0).
Un caractère de "mot" sera une lettre, un chiffre ou le
caractère souligné, c'est-à-dire un
caractère qui pourra être une partie d'un mot Perl. La
définition des lettres et chiffres est définie par les
tables de caractères de PCRE, et peut varier suivant la table
locale de caractères. Par exemple, dans la configuration "français" ("fr"),
certains caractères ont des codes supérieurs à
128, pour les caractères accentués, et ils seront compris
par le métacaractère \w
.
Ces séquences de caractères peuvent apparaître à l'intérieur ou à l'extérieur des classes de caractères. Elles remplacent à chaque fois un caractère du type correspondant. Si cette séquence est placée en fin de masque, et qu'il n'y a plus de caractère à comparer dans la chaîne sujet, la recherche échoue.
La quatrième utilisation de l'antislash intervient lors d'assertions simples. Une assertion impose une condition à un certain point, sans remplacer de caractère. L'utilisation de sous-masques pour réaliser des assertions plus complexes est décrite plus bas. Les assertions avec antislash sont les suivantes :
Ces assertions ne peuvent pas apparaître dans une classe de
caractères (mais "\b
" a une autre signification à
l'intérieur d'une classe de caractères).
Une limite de mot est un emplacement dans la chaîne sujet ou un
caractère et son suivant ne sont pas en même temps des
caractères de mot (\w
), ou le contraire (\W
)
(on peut le voir comme \w\W
ou \W\w
), ou encore le
premier ou le dernier caractère est un caractère mot (\w
).
Les assertions \A
, \Z
, et
\z
diffèrent des métacaractères
^
et $
(décrit dans les ancres)
dans la mesure où ils ne sont pas dépendants des options, notamment
PCRE_MULTILINE
ou PCRE_DOLLAR_ENDONLY.
La différence entre \Z
et
\z
tient au fait que \Z
recherche
les positions avant les nouvelles lignes et à la fin de la
chaîne sujet, tandis que \z
ne recherche
que la fin de la chaîne.
L'assertion \G
est réalisée uniquement lorsque
la position courante de l'occurrence trouvée est au début de l'occurrence,
comme spécifié par l'argument offset
de la
fonction preg_match(). Elle diffère de \A
lorsque la valeur du paramètre offset
est différente
de zéro.
\Q
et \E
peuvent être utilisés
pour ignorer les métacaractères dans le masque.
Par exemple : \w+\Q.$.\E$
recherchera un ou plusieurs
caractères suivis par la chaîne littérale .$.
et ancrés à la
fin de la chaîne.
Il est à noter que ceci ne change pas le comportement des délimiteurs ;
par exemple le masque #\Q#\E#$
n'est pas valide, car
le second #
marque la fin du masque, et que
\E#
est interprété comme un modificateur invalide.
\K
peut être utilisé pour réinitialiser le résultat
Par exemple, le masque foo\Kbar
trouve
"foobar", mais reporte qu'il a trouvé "bar". L'utilisation de
\K
n'interfère pas avec la configuration des sous-chaînes capturantes.
Par exemple, lorsque le masque (foo)\Kbar
trouve "foobar", la première sous-chaîne sera toujours "foo".
"line break" is ill-defined:
-- Windows uses CR+LF (\r\n)
-- Linux LF (\n)
-- OSX CR (\r)
Little-known special character:
\R in preg_* matches all three.
preg_match( '/^\R$/', "match\nany\\n\rline\r\nending\r" ); // match any line endings
Significantly updated version (with new $pat4 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 ($) 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'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi'; // Slightly better
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org when used improperly
$pat4='/\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
$pat5='/\w\v?$/mi';
$pat6='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment (described on pcre.org and en.wikipedia.org)
$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);
$t=preg_match_all($pat6, $str, $m6);
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)
."\n6 !!! $pat6 ($t): ".print_r($m6[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 and $pat4 (\R), $pat5 (\v) and altered newline option in $pat6 ((*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(?=\R)/i (6): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
)
5 !!! /\w\v?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
6 !!! /(*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.
A non breaking space is not considered as a space and cannot be caught by \s.
it can be found with :
- [\xc2\xa0] in utf-8
- \x{00a0} in unicode
As \v matches both single char line ends (CR, LF) and double char (CR+LF, LF+CR), it is not a fixed length atom (eg. is not allowed in lookbehind assertions).
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).
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'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi';
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org
$pat4='/\w\v?$/mi';
$pat5='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment
$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 among 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.