web-dev-qa-db-fra.com

Comment obtenir une sous-chaîne entre deux chaînes en PHP?

J'ai besoin d'une fonction qui retourne la sous-chaîne entre deux mots (ou deux caractères) . Je me demande s'il existe une fonction php qui permet d'atteindre cet objectif. Je ne veux pas penser à regex (bon, je pourrais en faire un, mais je ne pense vraiment pas que ce soit la meilleure façon de faire). En pensant aux fonctions strpos et substr ..__, voici un exemple:

$string = "foo I wanna a cake foo";

Nous appelons la fonction: $substring = getInnerSubstring($string,"foo"); 
Il revient: "Je veux un gâteau".

Merci d'avance. 

Mise à jour: Eh bien, jusqu’à présent, je peux obtenir une sous-chaîne de deux mots en une seule chaîne, me permettez-vous de me laisser aller un peu plus loin et de demander si je peux étendre l’utilisation de getInnerSubstring($str,$delim) pour obtenir toutes les chaînes comprises entre delim value, exemple:

$string =" foo I like php foo, but foo I also like asp foo, foo I feel hero  foo";

Je reçois un tableau comme {"I like php", "I also like asp", "I feel hero"}.

107
Nadjib Mami

Si les chaînes sont différentes (ie: [foo] & [/ foo]), jetez un coup d'œil à ce post de Justin Cook .

function get_string_between($string, $start, $end){
    $string = ' ' . $string;
    $ini = strpos($string, $start);
    if ($ini == 0) return '';
    $ini += strlen($start);
    $len = strpos($string, $end, $ini) - $ini;
    return substr($string, $ini, $len);
}

$fullstring = 'this is my [tag]dog[/tag]';
$parsed = get_string_between($fullstring, '[tag]', '[/tag]');

echo $parsed; // (result = dog)

Les expressions régulières sont la voie à suivre:

$str = 'before-str-after';
if (preg_match('/before-(.*?)-after/', $str, $match) == 1) {
    echo $match[1];
}

onlinePhp

48
nkkollaw
function getBetween($string, $start = "", $end = ""){
    if (strpos($string, $start)) { // required if $start not exist in $string
        $startCharCount = strpos($string, $start) + strlen($start);
        $firstSubStr = substr($string, $startCharCount, strlen($string));
        $endCharCount = strpos($firstSubStr, $end);
        if ($endCharCount == 0) {
            $endCharCount = strlen($firstSubStr);
        }
        return substr($firstSubStr, 0, $endCharCount);
    } else {
        return '';
    }
}

Exemple d'utilisation:

echo getBetween("a","c","abc"); // returns: 'b'

echo getBetween("h","o","hello"); // returns: 'ell'

echo getBetween("a","r","World"); // returns: ''
22
daniel
function getInnerSubstring($string,$delim){
    // "foo a foo" becomes: array(""," a ","")
    $string = explode($delim, $string, 3); // also, we only need 2 items at most
    // we check whether the 2nd is set and return it, otherwise we return an empty string
    return isset($string[1]) ? $string[1] : '';
}

Exemple d'utilisation:

var_dump(getInnerSubstring('foo Hello world foo','foo'));
// prints: string(13) " Hello world "

Si vous souhaitez supprimer les espaces blancs environnants, utilisez trim. Exemple:

var_dump(trim(getInnerSubstring('foo Hello world foo','foo')));
// prints: string(11) "Hello world"
13
Christian
function getInbetweenStrings($start, $end, $str){
    $matches = array();
    $regex = "/$start([a-zA-Z0-9_]*)$end/";
    preg_match_all($regex, $str, $matches);
    return $matches[1];
}

par exemple, vous voulez le tableau de chaînes (clés) entre @@ à la suite par exemple, où '/' ne se situe pas entre les deux

$str = "C://@@ad_custom_attr1@@/@@upn@@/@@samaccountname@@";
$str_arr = getInbetweenStrings('@@', '@@', $str);

print_r($str_arr);
12
Ravi Verma

J'aime les solutions d'expression régulières, mais aucune des autres ne me convient.

Si vous savez qu'il n'y aura qu'un seul résultat, vous pouvez utiliser ce qui suit:

$between = preg_replace('/(.*)BEFORE(.*)AFTER(.*)/sm', '\2', $string);

Changer AVANT et APRÈS aux délimiteurs désirés.

Gardez également à l'esprit que cette fonction renverra la chaîne entière au cas où rien ne correspond.

Cette solution est multiligne mais vous pouvez jouer avec les modificateurs en fonction de vos besoins.

6
ragnar

Si vous utilisez foo comme délimiteur, examinez explode() 

6
oblig
<?php
  function getBetween($content,$start,$end){
    $r = explode($start, $content);
    if (isset($r[1])){
        $r = explode($end, $r[1]);
        return $r[0];
    }
    return '';
  }
?>

Exemple: 

<?php 
  $content = "Try to find the guy in the middle with this function!";
  $start = "Try to find ";
  $end = " with this function!";
  $output = getBetween($content,$start,$end);
  echo $output;
?>

Cela retournera "le gars au milieu".

5
user1366605

utilisez la fonction strstr php deux fois.

$value = "This is a great day to be alive";
$value = strstr($value, "is"); //gets all text from needle on
$value = strstr($value, "be", true); //gets all text before needle
echo $value;

sorties: "is a great day to"

4
Bryce

Si vous avez plusieurs récurrences d'une même chaîne et que vous avez un modèle différent [début] et [\ fin]. Voici une fonction qui sort un tableau.

function get_string_between($string, $start, $end){
    $split_string       = explode($end,$string);
    foreach($split_string as $data) {
         $str_pos       = strpos($data,$start);
         $last_pos      = strlen($data);
         $capture_len   = $last_pos - $str_pos;
         $return[]      = substr($data,$str_pos+1,$capture_len);
    }
    return $return;
}
3
noelthegreat

Voici une fonction

function getInnerSubstring($string, $boundstring, $trimit=false) {
    $res = false;
    $bstart = strpos($string, $boundstring);
    if ($bstart >= 0) {
        $bend = strrpos($string, $boundstring);
        if ($bend >= 0 && $bend > $bstart)
            $res = substr($string, $bstart+strlen($boundstring), $bend-$bstart-strlen($boundstring));
    }
    return $trimit ? trim($res) : $res;
}

Utilisez-le comme

$string = "foo I wanna a cake foo";
$substring = getInnerSubstring($string, "foo");

echo $substring;

Sortie (notez qu'il renvoie des espaces devant et à la fin de votre chaîne, le cas échéant)

Je veux un gâteau

Si vous voulez ajuster le résultat, utilisez la fonction comme

$substring = getInnerSubstring($string, "foo", true);

Résultat: Cette fonction retournera false si $boundstring n'a pas été trouvé dans $string ou si $boundstring n'existe qu'une seule fois dans $string, sinon il renvoie une sous-chaîne entre la première et la dernière occurrence de $boundstring dans $string.


Références

3
Wh1T3h4Ck5

J'utilise 

if (count(explode("<TAG>", $input))>1){
      $content = explode("</TAG>",explode("<TAG>", $input)[1])[0];
}else{
      $content = "";
}

Sous-titre <TAG> pour le délimiteur que vous voulez.

1
Ángel R.G.

Utilisation:

<?php

$str = "...server daemon started with pid=6849 (parent=6848).";
$from = "pid=";
$to = "(";

echo getStringBetween($str,$from,$to);

function getStringBetween($str,$from,$to)
{
    $sub = substr($str, strpos($str,$from)+strlen($from),strlen($str));
    return substr($sub,0,strpos($sub,$to));
}

?>
1
Salim

C'est la fonction que j'utilise pour cela. J'ai combiné deux réponses en une seule fonction pour un ou plusieurs délimiteurs.

function getStringBetweenDelimiters($p_string, $p_from, $p_to, $p_multiple=false){
    //checking for valid main string  
    if (strlen($p_string) > 0) {
        //checking for multiple strings 
        if ($p_multiple) {
            // getting list of results by end delimiter
            $result_list = explode($p_to, $p_string);
            //looping through result list array 
            foreach ( $result_list AS $rlkey => $rlrow) {
                // getting result start position
                $result_start_pos   = strpos($rlrow, $p_from);
                // calculating result length
                $result_len         =  strlen($rlrow) - $result_start_pos;

                // return only valid rows
                if ($result_start_pos > 0) {
                    // cleanying result string + removing $p_from text from result
                    $result[] =   substr($rlrow, $result_start_pos + strlen($p_from), $result_len);                 
                }// end if 
            } // end foreach 

        // if single string
        } else {
            // result start point + removing $p_from text from result
            $result_start_pos   = strpos($p_string, $p_from) + strlen($p_from);
            // lenght of result string
            $result_length      = strpos($p_string, $p_to, $result_start_pos);
            // cleaning result string
            $result             = substr($p_string, $result_start_pos+1, $result_length );
        } // end if else 
    // if empty main string
    } else {
        $result = false;
    } // end if else 

    return $result;


} // end func. get string between

Pour une utilisation simple (retourne deux): 

$result = getStringBetweenDelimiters(" one two three ", 'one', 'three');

Pour que chaque ligne d'une table aboutisse à un tableau: 

$result = getStringBetweenDelimiters($table, '<tr>', '</tr>', true);
1
Szekelygobe

Pas un php pro. mais j'ai récemment couru dans ce mur aussi et c'est ce que je suis venu avec.

function tag_contents($string, $tag_open, $tag_close){
   foreach (explode($tag_open, $string) as $key => $value) {
       if(strpos($value, $tag_close) !== FALSE){
            $result[] = substr($value, 0, strpos($value, $tag_close));;
       }
   }
   return $result;
}

$string = "i love cute animals, like [animal]cat[/animal],
           [animal]dog[/animal] and [animal]panda[/animal]!!!";

echo "<pre>";
print_r(tag_contents($string , "[animal]" , "[/animal]"));
echo "</pre>";

//result
Array
(
    [0] => cat
    [1] => dog
    [2] => panda
)
1
Light93

Dans le style strpos de PHP, ceci retournera false si la marque de début sm ou la marque de fin em sont introuvables.

Ce résultat (false) est différent d'une chaîne vide qui correspond à ce que vous obtenez s'il n'y a rien entre les marques de début et de fin.

function between( $str, $sm, $em )
{
    $s = strpos( $str, $sm );
    if( $s === false ) return false;
    $s += strlen( $sm );
    $e = strpos( $str, $em, $s );
    if( $e === false ) return false;
    return substr( $str, $s, $e - $s );
}

La fonction ne renverra que le premier match.

Il est évident mais il convient de mentionner que la fonction cherchera d'abord sm et ensuite em.

Cela signifie que vous risquez de ne pas obtenir le résultat/le comportement souhaité si vous devez effectuer une recherche préalable sur em, puis analyser la chaîne en arrière pour rechercher sm.

1
Paolo

Amélioration de la réponse de Alejandro . Vous pouvez laisser les arguments $start ou $end vides et utiliser le début ou la fin de la chaîne.

echo get_string_between("Hello my name is bob", "my", ""); //output: " name is bob"

private function get_string_between($string, $start, $end){ // Get
    if($start != ''){ //If $start is empty, use start of the string
        $string = ' ' . $string;
        $ini = strpos($string, $start);
        if ($ini == 0) return '';
        $ini += strlen($start);
    }
    else{
        $ini = 0;
    }

    if ($end == '') { //If $end is blank, use end of string
        return substr($string, $ini);
    }
    else{
        $len = strpos($string, $end, $ini) - $ini; //Work out length of string
        return substr($string, $ini, $len);
    }
}
1
Rikki Masters

Un peu amélioré le code de GarciaWebDev et Henry Wang. Si $ start ou $ end est donné, la fonction renvoie les valeurs du début ou de la fin de la chaîne $. L'option Inclusive est également disponible, que nous voulions inclure le résultat de la recherche ou non: 

function get_string_between ($string, $start, $end, $inclusive = false){
    $string = " ".$string;

    if ($start == "") { $ini = 0; }
    else { $ini = strpos($string, $start); }

    if ($end == "") { $len = strlen($string); }
    else { $len = strpos($string, $end, $ini) - $ini;}

    if (!$inclusive) { $ini += strlen($start); }
    else { $len += strlen($end); }

    return substr($string, $ini, $len);
}
1
Julius Tilvikas

Je dois ajouter quelque chose au poste de Julius Tilvikas. J'ai cherché une solution comme celle-ci qu'il a décrite dans son post. Mais je pense qu'il y a une erreur. Je ne reçois pas vraiment la chaîne entre deux chaînes, je reçois aussi plus avec cette solution, car je dois soustraire la longueur de la chaîne de départ. Quand fais ceci, j'obtiens vraiment la chaîne entre deux chaînes.

Voici mes modifications de sa solution:

function get_string_between ($string, $start, $end, $inclusive = false){
    $string = " ".$string;

    if ($start == "") { $ini = 0; }
    else { $ini = strpos($string, $start); }

    if ($end == "") { $len = strlen($string); }
    else { $len = strpos($string, $end, $ini) - $ini - strlen($start);}

    if (!$inclusive) { $ini += strlen($start); }
    else { $len += strlen($end); }

    return substr($string, $ini, $len);
}

Greetz

V

1
Der_V

Essayez ceci, son travail pour moi, obtenir des données entre test Word. 

$str = "Xdata test HD01 test 1data";  
$result = explode('test',$str);   
print_r($result);
echo $result[1];
1
Dave

Avec quelques erreurs de capture. Plus précisément, la plupart des fonctions présentées requièrent $ end pour exister, alors que dans mon cas, j'avais besoin que ce soit optionnel. Utilisez ceci car $ end est optionnel et évaluez-le pour FALSE si $ start n’existe pas du tout:

function get_string_between( $string, $start, $end ){
    $string = " " . $string;
    $start_ini = strpos( $string, $start );
    $end = strpos( $string, $end, $start+1 );
    if ($start && $end) {
        return substr( $string, $start_ini + strlen($start), strlen( $string )-( $start_ini + $end ) );
    } elseif ( $start && !$end ) {
        return substr( $string, $start_ini + strlen($start) );
    } else {
        return FALSE;
    }

}
0
NotaGuruAtAll

Une grande majorité des réponses ici ne répondent pas à la partie modifiée, je suppose qu'elles ont été ajoutées auparavant. Cela peut être fait avec regex, comme le mentionne une réponse. J'ai eu une approche différente.


Cette fonction cherche $ string et trouve le première chaîne entre $ start et $ end, en commençant à $ offset position. Il met ensuite à jour la position $ offset pour pointer vers le début du résultat. Si $ includeDelimiters est true, les délimiteurs sont inclus dans le résultat.

Si la chaîne $ start ou $ end n'est pas trouvée, elle renvoie null. Il renvoie également null si $ string, $ start ou $ end sont une chaîne vide.

function str_between(string $string, string $start, string $end, bool $includeDelimiters = false, int &$offset = 0): ?string
{
    if ($string === '' || $start === '' || $end === '') return null;

    $startLength = strlen($start);
    $endLength = strlen($end);

    $startPos = strpos($string, $start, $offset);
    if ($startPos === false) return null;

    $endPos = strpos($string, $end, $startPos + $startLength);
    if ($endPos === false) return null;

    $length = $endPos - $startPos + ($includeDelimiters ? $endLength : -$startLength);
    if (!$length) return '';

    $offset = $startPos + ($includeDelimiters ? 0 : $startLength);

    $result = substr($string, $offset, $length);

    return ($result !== false ? $result : null);
}

La fonction suivante recherche toutes les chaînes qui se trouvent entre deux chaînes (sans chevauchement). Il nécessite la fonction précédente et les arguments sont les mêmes. Après exécution, $ offset pointe vers le début de la dernière chaîne de résultat trouvée.

function str_between_all(string $string, string $start, string $end, bool $includeDelimiters = false, int &$offset = 0): ?array
{
    $strings = [];
    $length = strlen($string);

    while ($offset < $length)
    {
        $found = str_between($string, $start, $end, $includeDelimiters, $offset);
        if ($found === null) break;

        $strings[] = $found;
        $offset += strlen($includeDelimiters ? $found : $start . $found . $end); // move offset to the end of the newfound string
    }

    return $strings;
}

Exemples:

str_between_all('foo 1 bar 2 foo 3 bar', 'foo', 'bar') donne [' 1 ', ' 3 '].

str_between_all('foo 1 bar 2', 'foo', 'bar') donne [' 1 '].

str_between_all('foo 1 foo 2 foo 3 foo', 'foo', 'foo') donne [' 1 ', ' 3 '].

str_between_all('foo 1 bar', 'foo', 'foo') donne [].

0
Quirinus

La version UTF-8 de la réponse de @Alejandro Iglesias fonctionnera pour les caractères non latins:

function get_string_between($string, $start, $end){
    $string = ' ' . $string;
    $ini = mb_strpos($string, $start, 0, 'UTF-8');
    if ($ini == 0) return '';
    $ini += mb_strlen($start, 'UTF-8');
    $len = mb_strpos($string, $end, $ini, 'UTF-8') - $ini;
    return mb_substr($string, $ini, $len, 'UTF-8');
}

$fullstring = 'this is my [tag]dog[/tag]';
$parsed = get_string_between($fullstring, '[tag]', '[/tag]');

echo $parsed; // (result = dog)
0
NXT

une version révisée de ce que Alejandro García Iglesias a mis. 

Cela vous permet de choisir un emplacement spécifique de la chaîne que vous voulez obtenir en fonction du nombre de fois que le résultat est trouvé. 

function get_string_between_pos($string, $start, $end, $pos){
    $cPos = 0;
    $ini = 0;
    $result = '';
    for($i = 0; $i < $pos; $i++){
      $ini = strpos($string, $start, $cPos);
      if ($ini == 0) return '';
      $ini += strlen($start);
      $len = strpos($string, $end, $ini) - $ini;
      $result = substr($string, $ini, $len);
      $cPos = $ini + $len;
    }
    return $result;
  }

usage: 

$text = 'string has start test 1 end and start test 2 end and start test 3 end to print';

//get $result = "test 1"
$result = $this->get_string_between_pos($text, 'start', 'end', 1);

//get $result = "test 2"
$result = $this->get_string_between_pos($text, 'start', 'end', 2);

//get $result = "test 3"
$result = $this->get_string_between_pos($text, 'start', 'end', 3);

strpos a une entrée optionnelle supplémentaire pour démarrer la recherche à un moment donné. Je stocke donc la position précédente dans $ cPos. Ainsi, lorsque la boucle for vérifie à nouveau, elle commence à la fin de celle où elle s’est arrêtée. 

0
SwiftNinjaPro

J'ai eu quelques problèmes avec la fonction get_string_between (), utilisée ici. Alors je suis venu avec ma propre version. Peut-être que cela pourrait aider des personnes dans le même cas que le mien.

protected function string_between($string, $start, $end, $inclusive = false) { 
   $fragments = explode($start, $string, 2);
   if (isset($fragments[1])) {
      $fragments = explode($end, $fragments[1], 2);
      if ($inclusive) {
         return $start.$fragments[0].$end;
      } else {
         return $fragments[0];
      }
   }
   return false;
}
0
KmeCnin

Utilisation: 

function getdatabetween($string, $start, $end){
    $sp = strpos($string, $start)+strlen($start);
    $ep = strpos($string, $end)-strlen($start);
    $data = trim(substr($string, $sp, $ep));
    return trim($data);
}
$dt = "Find string between two strings in PHP";
echo getdatabetween($dt, 'Find', 'in PHP');
0
Pankaj Raturi

écrit ces derniers quelque temps, il a trouvé très utile pour un large éventail d'applications.

<?php

// substr_getbykeys() - Returns everything in a source string that exists between the first occurance of each of the two key substrings
//          - only returns first match, and can be used in loops to iterate through large datasets
//          - arg 1 is the first substring to look for
//          - arg 2 is the second substring to look for
//          - arg 3 is the source string the search is performed on.
//          - arg 4 is boolean and allows you to determine if returned result should include the search keys.
//          - arg 5 is boolean and can be used to determine whether search should be case-sensative or not.
//

function substr_getbykeys($key1, $key2, $source, $returnkeys, $casematters) {
    if ($casematters === true) {
        $start = strpos($source, $key1);
        $end = strpos($source, $key2);
    } else {
        $start = stripos($source, $key1);
        $end = stripos($source, $key2);
    }
    if ($start === false || $end === false) { return false; }
    if ($start > $end) {
        $temp = $start;
        $start = $end;
        $end = $temp;
    }
    if ( $returnkeys === true) {
        $length = ($end + strlen($key2)) - $start;
    } else {
        $start = $start + strlen($key1);
        $length = $end - $start;
    }
    return substr($source, $start, $length);
}

// substr_delbykeys() - Returns a copy of source string with everything between the first occurance of both key substrings removed
//          - only returns first match, and can be used in loops to iterate through large datasets
//          - arg 1 is the first key substring to look for
//          - arg 2 is the second key substring to look for
//          - arg 3 is the source string the search is performed on.
//          - arg 4 is boolean and allows you to determine if returned result should include the search keys.
//          - arg 5 is boolean and can be used to determine whether search should be case-sensative or not.
//

function substr_delbykeys($key1, $key2, $source, $returnkeys, $casematters) {
    if ($casematters === true) {
        $start = strpos($source, $key1);
        $end = strpos($source, $key2);
    } else {
        $start = stripos($source, $key1);
        $end = stripos($source, $key2);
    }
    if ($start === false || $end === false) { return false; }
    if ($start > $end) {
        $temp = $start; 
        $start = $end;
        $end = $temp;
    }
    if ( $returnkeys === true) {
        $start = $start + strlen($key1);
        $length = $end - $start;
    } else {
        $length = ($end + strlen($key2)) - $start;  
    }
    return substr_replace($source, '', $start, $length);
}
?>
0
Dave

Vous avez la meilleure solution pour cela de tonyspiro

function getBetween($content,$start,$end){
   $r = explode($start, $content);
   if (isset($r[1])){
       $r = explode($end, $r[1]);
       return $r[0];
   }
   return '';
}
0
Som