web-dev-qa-db-fra.com

Bonne façon d'échapper à la barre oblique inverse [\] PHP regex?

Par simple curiosité, j'essaie de déterminer quel est le bon moyen d'échapper à une barre oblique inversée pour l'utiliser dans un modèle d'expression régulière PHP comme suit:

TEST 01: (3 anti-slash)

$pattern = "/^[\\\]{1,}$/";
$string = '\\';

// ----- RETURNS A MATCH -----

TEST 02: (4 anti-slash)

$pattern = "/^[\\\\]{1,}$/";
$string = '\\';

// ----- ALSO RETURNS A MATCH -----

Selon les articles ci-dessous, 4 est censé être la bonne façon, mais ce qui me dérange, c'est que les deux tests ont donné une correspondance. Si les deux ont raison, alors 4 est-il le moyen préféré?

RESSOURCES:

26
Mahmoud Tahan

Le fait est que vous utilisez une classe de caractères, [], de sorte que le nombre de barres obliques inverses littérales incorporées dans celle-ci importe peu, elle sera traitée comme une seule barre oblique inversée.

par exemple. les deux expressions rationnelles suivantes:

/[a]/
/[aa]/

sont à toutes fins utiles identiques en ce qui concerne le moteur de regex. Les classes de caractères prennent une liste de caractères et les "réduisent" pour les faire correspondre à un seul caractère, le long des lignes de "pour le caractère actuel considéré, s'agit-il de l'un des caractères listés dans le []?". Si vous énumérez deux barres obliques inverses dans la classe, alors ce sera "le caractère est-il une barre oblique ou est-ce une barre oblique inversée?".

4
Marc B
// PHP 5.4.1

// Either three or four \ can be used to match a '\'.
echo preg_match( '/\\\/', '\\' );        // 1
echo preg_match( '/\\\\/', '\\' );       // 1

// Match two backslashes `\\`.
echo preg_match( '/\\\\\\/', '\\\\' );   // Warning: No ending delimiter '/' found
echo preg_match( '/\\\\\\\/', '\\\\' );  // 1
echo preg_match( '/\\\\\\\\/', '\\\\' ); // 1

// Match one backslash using a character class.
echo preg_match( '/[\\]/', '\\' );       // 0
echo preg_match( '/[\\\]/', '\\' );      // 1  
echo preg_match( '/[\\\\]/', '\\' );     // 1

Lorsque vous utilisez trois barres obliques inverses pour faire correspondre un '\', le modèle ci-dessous est interprété comme correspondant à un '\' suivi d'un 's'.

echo preg_match( '/\\\\s/', '\\ ' );    // 0  
echo preg_match( '/\\\\s/', '\\s' );    // 1  

Lorsque vous utilisez quatre barres obliques inverses pour faire correspondre un '\', le modèle ci-dessous est interprété comme correspondant à un '\' suivi d'un caractère d'espacement.

echo preg_match( '/\\\\\s/', '\\ ' );   // 1
echo preg_match( '/\\\\\s/', '\\s' );   // 0

La même chose s'applique si à l'intérieur d'une classe de personnage.

echo preg_match( '/[\\\\s]/', ' ' );   // 0 
echo preg_match( '/[\\\\\s]/', ' ' );  // 1 

_ {Aucun des résultats ci-dessus n'est affecté par la présence de chaînes entre guillemets au lieu de guillemets simples.

Conclusions:
Que ce soit à l'intérieur ou à l'extérieur d'une classe de caractères entre crochets, une barre oblique inverse littérale peut être associée à l'aide de trois barres obliques inverses uniquement '\\\', sauf si le caractère suivant du modèle est également inversé, auquel cas la barre oblique inversée littérale doit être associée à quatre barres obliques inverses. 

Recommandation:
Utilisez toujours quatre barres obliques inverses '\\\\' dans un motif regex lorsque vous cherchez à faire correspondre une barre oblique inversée.

Séquences d'échappement .

41
MikeM

Pour éviter ce genre de code peu clair, vous pouvez utiliser\x5c Comme ça :)

echo preg_replace( '/\x5c\w+\.php$/i', '<b>${0}</b>', __FILE__ );

J'ai étudié cela il y a des années. En effet, la première barre oblique inverse échappe à la deuxième et ils forment ensemble un caractère «vrai baclkslash» et ce vrai masque échappe au troisième. Donc, comme par magie, 3 barres obliques inversées fonctionnent. 

Toutefois, il est conseillé d'utiliser 4 barres obliques inverses au lieu des 3 barres obliques inverses ambiguës.

Si je me trompe à propos de quelque chose, n'hésitez pas à me corriger.

1
Scott Chu

Vous pouvez également utiliser les éléments suivants 

$regexp = <<<EOR
schemaLocation\s*=\s*["'](.*?)["']
EOR;
preg_match_all("/".$regexp."/", $xml, $matches);
print_r($matches);

mots-clés: dochere, nowdoc

0
test30