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?
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];
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.
Utilisez une expression régulière:
if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
$text = $match[1];
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"
}
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.
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:
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 )