85 votes

PHP : Meilleur moyen d'extraire le texte entre parenthèses ?

Quel est le moyen le plus efficace d'extraire du texte entre parenthèses ? Imaginons que je veuille extraire la chaîne "texte" de la chaîne "ignore tout sauf ceci (texte)" de la manière la plus efficace possible.

Jusqu'à présent, le mieux que j'ai pu trouver est ceci :

$fullString = "ignore everything except this (text)";
$start = strpos('(', $fullString);
$end = strlen($fullString) - strpos(')', $fullString);

$shortString = substr($fullString, $start, $end);

Y a-t-il une meilleure façon de procéder ? Je sais qu'en général, l'utilisation de l'expression rationnelle a tendance à être moins efficace, mais à moins que je puisse réduire le nombre d'appels de fonction, ce serait peut-être la meilleure approche ? Qu'en pensez-vous ?

0 votes

Vous pourriez trouver s($fullString)->between("(", ")") utile, comme on le trouve dans cette bibliothèque autonome .

150voto

Owen Points 36009

À moins que vous ne fassiez suffisamment d'itérations pour que cela devienne un énorme problème de performance, c'est juste plus facile à coder (et à comprendre quand vous y repensez).

$text = 'ignore everything except this (text)';
preg_match('#\((.*?)\)#', $text, $match);
print $match[1];

1 votes

Non, ce n'est pas le cas : . ne correspond qu'à un seul caractère.

1 votes

Pas nécessairement, ? est une correspondance paresseuse. Sans elle, une chaîne comme 'ignore (tout) sauf ceci (texte)', la correspondance serait finalement 'tout) sauf ceci (texte)'.

1 votes

Bon à savoir. Cela devrait éviter tous ces "not" carrés. Par exemple, /src="([^"]*)"/ est maintenant remplacé par /src="(.* ?)"/ :D

15voto

Edward Z. Yang Points 13760

Donc, en fait, le code que vous avez posté ne fonctionne pas : substr()'s Les paramètres sont $string, $start et Longueur y strpos()'s Les paramètres sont $haystack , $needle . Légèrement modifié :

$str = "ignore everything except this (text)";
$start  = strpos($str, '(');
$end    = strpos($str, ')', $start + 1);
$length = $end - $start;
$result = substr($str, $start + 1, $length - 1);

Quelques subtilités : J'ai utilisé $start + 1 dans le paramètre de décalage afin d'aider PHP lors de l'exécution de l'opération. strpos() recherche sur la deuxième parenthèse ; nous incrémentons $start un et réduire $length pour exclure les parenthèses de la correspondance.

De plus, il n'y a pas de vérification d'erreur dans ce code : vous devrez vous assurer que $start et $end ne sont pas === faux avant d'effectuer le substr .

Quant à l'utilisation strpos/substr par rapport à l'expression régulière ; en termes de performances, ce code est bien meilleur qu'une expression régulière. Mais il est un peu plus compliqué. Je mange et je respire strpos/substr Je ne suis donc pas trop gêné, mais quelqu'un d'autre peut préférer la compacité d'une regex.

1 votes

Notez que si vous modifiez ce code pour utiliser strrpos (commence à partir de l'arrière de la chaîne) sur le $end alors il gèrera correctement les cas où il y a des parens à l'intérieur comme (bien c'est (très) gentil).

12voto

Rob Points 31432

Utilisez une expression régulière :

if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
    $text = $match[1];

4voto

rüff0 Points 184

Je pense que c'est le moyen le plus rapide d'obtenir les mots entre les premières parenthèses dans une chaîne de caractères.

$string = 'ignore everything except this (text)';
$string = explode(')', (explode('(', $string)[1]))[0];
echo $string;

3voto

Wiktor Stribiżew Points 100073

Les solutions regex déjà postées - \((.*?)\) et \(([^\)]+)\) - ne renvoient pas le le plus intime entre une parenthèse ouverte et une parenthèse fermée. Si une chaîne est Text (abc(xyz 123) ils les deux retourner a (abc(xyz 123) comme un match entier, et non (xyz 123) .

Le motif qui correspond aux sous-chaînes (à utiliser avec preg_match pour récupérer le premier et preg_match_all pour rechercher toutes les occurrences) entre parenthèses sans autres parenthèses ouvertes et fermées entre elles est, si la correspondance doit inclure des parenthèses :

\([^()]*\)

Ou bien, vous voulez obtenir des valeurs sans parenthèses :

\(([^()]*)\)        // get Group 1 values after a successful call to preg_match_all, see code below
\(\K[^()]*(?=\))    // this and the one below get the values without parentheses as whole matches 
(?<=\()[^()]*(?=\)) // less efficient, not recommended

Remplacer * con + s'il doit y avoir au moins 1 caractère entre ( et ) .

Détails :

  • \( - une parenthèse ouvrante (doit être échappée pour désigner une parenthèse littérale car elle est utilisée en dehors d'une classe de caractères)
  • [^()]* - zéro ou plus des caractères autres que ( et ) (notez ces ( et ) ne doivent pas être échappés à l'intérieur d'une classe de caractères comme à l'intérieur de celle-ci, ( et ) ne peuvent pas être utilisées pour spécifier un regroupement et sont traitées comme des parenthèses littérales)
  • \) - une parenthèse fermante (doit être échappée pour désigner une parenthèse littérale car elle est utilisée en dehors d'une classe de caractères).

Le site \(\K la partie dans une regex alternative correspond ( et omet de la valeur de correspondance (avec l'option \K opérateur de réinitialisation des correspondances). (?<=\() est un regard positif qui nécessite un ( pour apparaître immédiatement à gauche de l'emplacement actuel, mais l'icône ( n'est pas ajouté à la valeur de la correspondance puisque les motifs lookbehind (lookaround) ne sont pas consommés. (?=\() est un lookahead positif qui nécessite un ) pour apparaître immédiatement à droite de l'emplacement actuel.

Code PHP :

$fullString = 'ignore everything except this (text) and (that (text here))';
if (preg_match_all('~\(([^()]*)\)~', $fullString, $matches)) {
    print_r($matches[0]); // Get whole match values
    print_r($matches[1]); // Get Group 1 values
}

Sortie :

Array ( [0] => (text)  [1] => (text here) )
Array ( [0] => text    [1] => text here   )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X