web-dev-qa-db-fra.com

PHP: La meilleure façon d'extraire du texte entre parenthèses?

Quelle est la meilleure façon/la plus efficace d'extraire le texte entre parenthèses? Disons que je voulais obtenir la chaîne "text" de la chaîne "ignorez tout sauf ce (texte)" de la manière la plus efficace possible.

Jusqu'à présent, le meilleur que j'ai trouvé est le suivant:

$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 manière de faire cela? Je sais qu'en général, l'utilisation des expressions rationnelles 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? Pensées?

68
Wilco

je ferais juste une regex et j'en finirais. à moins que vous ne fassiez suffisamment d'itérations pour que cela devienne un énorme problème de performances, il est simplement plus facile de coder (et de comprendre quand vous y repensez)

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

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

$ str = "ignorer tout sauf ce (texte)"; 
 $ start = strpos ($ str, '('); 
 $ end = strpos ($ str, ')', $ start + 1); 
 $ Longueur = $ fin - $ début; 
 $ Résultat = substr ($ str, $ début + 1, $ longueur - 1);

Quelques subtilités: j'ai utilisé $start + 1 Dans le paramètre offset afin d'aider PHP out tout en faisant la recherche strpos() sur la deuxième parenthèse; on incrémente $start Un et réduisez $length Pour exclure les parenthèses de la correspondance.

De plus, il n'y a pas d'erreur lors de la vérification de ce code: vous voudrez vous assurer que $start Et $end Ne sont pas faux === avant d'effectuer le substr.

Quant à l'utilisation de strpos/substr Contre regex; en termes de performances, ce code battra une expression régulière haut la main. C'est un peu plus verbeux cependant. Je mange et je respire strpos/substr, Donc cela ne me dérange pas trop, mais quelqu'un d'autre peut préférer la compacité d'un regex.

12
Edward Z. Yang

Utilisez une expression régulière:

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

Ceci est un exemple de code pour extraire tout le texte entre '[' et ']' et le stocker 2 tableaux séparés (c'est-à-dire le texte entre parenthèses dans un tableau et le texte hors parenthèses dans un autre tableau)

   function extract_text($string)
   {
    $text_outside=array();
    $text_inside=array();
    $t="";
    for($i=0;$i<strlen($string);$i++)
    {
        if($string[$i]=='[')
        {
            $text_outside[]=$t;
            $t="";
            $t1="";
            $i++;
            while($string[$i]!=']')
            {
                $t1.=$string[$i];
                $i++;
            }
            $text_inside[] = $t1;

        }
        else {
            if($string[$i]!=']')
            $t.=$string[$i];
            else {
                continue;
            }

        }
    }
    if($t!="")
    $text_outside[]=$t;

    var_dump($text_outside);
    echo "\n\n";
    var_dump($text_inside);
  }

Sortie: extract_text ("bonjour comment allez-vous?"); produira:

array(1) {
  [0]=>
  string(18) "hello how are you?"
}

array(0) {
}

extract_text ("bonjour [http://www.google.com/test.mp3] comment allez-vous?"); produira

array(2) {
  [0]=>
  string(6) "hello "
  [1]=>
  string(13) " how are you?"
}


array(1) {
  [0]=>
  string(30) "http://www.google.com/test.mp3"
}
3
Sachin Murali G

Cette fonction peut être utile.

    public static function getStringBetween($str,$from,$to, $withFromAndTo = false)
    {
       $sub = substr($str, strpos($str,$from)+strlen($from),strlen($str));
       if ($withFromAndTo)
         return $from . substr($sub,0, strrpos($sub,$to)) . $to;
       else
         return substr($sub,0, strrpos($sub,$to));
    }
    $inputString = "ignore everything except this (text)";
    $outputString = getStringBetween($inputString, '(', ')'));
    echo $outputString; 
    //output will be test

    $outputString = getStringBetween($inputString, '(', ')', true));
    echo $outputString; 
    //output will be (test)

strpos () => qui est utilisé pour trouver la position de première occurrence dans une chaîne.

strrpos () => qui est utilisé pour trouver la position de première occurrence dans une chaîne.

1
vijay
function getStringsBetween($str, $start='[', $end=']', $with_from_to=true){
$arr = [];
$last_pos = 0;
$last_pos = strpos($str, $start, $last_pos);
while ($last_pos !== false) {
    $t = strpos($str, $end, $last_pos);
    $arr[] = ($with_from_to ? $start : '').substr($str, $last_pos + 1, $t - $last_pos - 1).($with_from_to ? $end : '');
    $last_pos = strpos($str, $start, $last_pos+1);
}
return $arr; }

c'est une petite amélioration par rapport à la réponse précédente qui renverra tous les modèles sous forme de tableau:

getStringsBetween ('[T] his [] is [test] string [pattern]') renverra:

0
user628176

Les solutions regex déjà publiées - \((.*?)\) et \(([^\)]+)\) - ne renvoient pas les chaînes au plus profond entre les crochets ouverts et fermés. Si une chaîne est Text (abc(xyz 123) ils les deuxretour un (abc(xyz 123) Dans sa totalité, et non (xyz 123).

Le modèle qui correspond aux sous-chaînes (à utiliser avec preg_match Pour récupérer la première et preg_match_all Pour récupérer toutes les occurrences) entre parenthèses sans autres parenthèses ouvrantes et fermées entre les deux est, si la correspondance doit inclure des parenthèses:

\([^()]*\)

Ou, 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

Remplacez * Par + S'il doit y avoir au moins 1 caractère entre ( Et ).

Détails :

  • \( - un crochet rond ouvrant (doit être échappé pour indiquer une parenthèse littérale car il est utilisé en dehors d'une classe de caractère)
  • [^()]* - zéro ou plus 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, ( et ) ne peuvent pas être utilisés pour spécifier un regroupement et sont traités comme des parenthèses littérales)
  • \) - un crochet rond de fermeture (doit être échappé pour indiquer une parenthèse littérale car il est utilisé en dehors d'une classe de caractères).

La partie \(\K Dans une expression régulière alternative correspond à ( Et omet de la valeur de correspondance (avec l'opérateur de réinitialisation de correspondance \K). (?<=\() Est un lookbehind positif qui nécessite qu'un ( Apparaisse immédiatement à gauche de l'emplacement actuel, mais le ( N'est pas ajouté à la valeur de correspondance depuis lookbehind (lookaround) les modèles ne consomment pas. (?=\() Est une anticipation positive qui nécessite qu'un caractère ) Apparaisse 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   )
0