3 votes

PHP Comprendre les callbacks - différence entre preg_replace_callback() et preg_match_all()

Je suis un peu confus quant à l'utilisation de preg_replace_callback()

J'ai un $content avec des URLs à l'intérieur.

Auparavant, j'utilisais

 $content = preg_match_all( '/(http[s]?:[^\s]*)/i', $content, $links );

 foreach ($links[1] as $link ) {
            // we have the link. find image , download, replace the content with image
            // echo '</br>LINK : '. $link;
            $url = esc_url_raw( $link );
            $url_name = parse_url($url); 
            $url_name = $description = $url_name['host'];// get rid of http://..
            $url = 'http://somescriptonsite/v1/' .  urlencode($url)   . '?w=' . $width ;
            } 

    return $url;

Mais ce dont j'ai vraiment besoin, c'est de REMPLACER l'URL originale par mon URL analysée...

J'ai donc essayé le preg_replace_callback :

function o99_simple_parse($content){

$content = preg_replace_callback( '/(http[s]?:[^\s]*)/i', 'o99_simple_callback', $content );

return $content;
}

et :

function o99_simple_callback($url){
    // how to get the URL which is actually the match? and width ??
        $url = esc_url_raw( $link );
        $url_name = parse_url($url); 
        $url_name = $description = $url_name['host'];// get rid of http://..
        $url = 'http://something' .  urlencode($url)   . '?w=' . $width ; 
        return $url; // what i really need to replace 
    }

J'ai supposé que la fonction de rappel fonctionnera de telle sorte que CHAQUE correspondance appellera la fonction de rappel (de manière récursive ?) et renverra les résultats, ce qui permettra de remplacer à la volée les URL dans $content par les URL analysées. $url de o99_simple_callbac() .

Mais un autre pregunta ici (et surtout ce commentaire ) a déclenché mes doutes.

Si le preg_replace_callback() passe en fait le tableau entier de correspondances, alors quelle est la différence entre ce que j'ai utilisé précédemment ( preg_match_all() dans le premier exemple) et l'exemple de rappel ?

Qu'est-ce que j'ai manqué ou mal compris ? Quelle serait la manière correcte de remplacer les URLs trouvés dans $content avec les urls analysées ?

4voto

Andrew Cheong Points 11331

Les autres réponses ont peut-être été suffisantes, mais laissez-moi vous en donner une autre en utilisant un exemple plus simple.

Disons que nous avons les données suivantes dans $subject ,

RECORD Male 1987-11-29 New York
RECORD Female 1987-07-13 Tennessee
RECORD Female 1990-04-14 New York

et l'expression régulière suivante dans $pattern ,

/RECORD (Male|Female) (\d\d\d\d)-(\d\d)-(\d\d) ([\w ]+)/

Comparons trois approches.

preg_match_all

D'abord, la vanille preg_match_all :

preg_match_all($pattern, $subject, $matches);

Voici ce que $matches s'avère être :

Array
(
    [0] => Array
        (
            [0] => RECORD Male 1987-11-29 New York
            [1] => RECORD Female 1987-07-13 Tennessee
            [2] => RECORD Female 1990-04-14 New York
        )

    [1] => Array
        (
            [0] => Male
            [1] => Female
            [2] => Female
        )

    [2] => Array
        (
            [0] => 1987
            [1] => 1987
            [2] => 1990
        )

    [3] => Array
        (
            [0] => 11
            [1] => 07
            [2] => 04
        )

    [4] => Array
        (
            [0] => 29
            [1] => 13
            [2] => 14
        )

    [5] => Array
        (
            [0] => New York
            [1] => Tennessee
            [2] => New York
        )

)

Qu'il s'agisse du champ "sexe" dans mon exemple ou du champ "URL" dans le vôtre, il est clair que le fait de parcourir en boucle les champs suivants $matches[1] itère à travers juste ce domaine :

foreach ($matches[1] as $match)
{
    $gender = $match;
    // ...
}

Cependant, comme vous l'avez remarqué, les changements que vous apportez à $matches[1] même si vous avez itéré à travers ses sous-arrays par référence, est-ce que no réfléchir $subject , c'est-à-dire vous ne pouvez pas effectuer de remplacements via preg_match_all .

preg_match_all avec PREG_SET_ORDER

Avant de sauter dans preg_replace_callback Cependant, jetons un coup d'œil à l'un des éléments suivants preg_match_all Les drapeaux les plus couramment utilisés par l'UE, PREG_SET_ORDER .

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);

Cette production est (apparemment) complètement différente !

Array
(
    [0] => Array
        (
            [0] => RECORD Male 1987-11-29 New York
            [1] => Male
            [2] => 1987
            [3] => 11
            [4] => 29
            [5] => New York
        )

    [1] => Array
        (
            [0] => RECORD Female 1987-07-13 Tennessee
            [1] => Female
            [2] => 1987
            [3] => 07
            [4] => 13
            [5] => Tennessee
        )

    [2] => Array
        (
            [0] => RECORD Female 1990-04-14 New York
            [1] => Female
            [2] => 1990
            [3] => 04
            [4] => 14
            [5] => New York
        )

)

Maintenant, chaque sous-réseau contient le set de groupes de capture par match par opposition à l'ensemble des correspond à par groupe de capture . (En d'autres termes, il s'agit de la transposition de l'autre tableau). Si vous vouliez jouer avec le sexe (ou l'URL) de chaque match, vous devriez maintenant écrire ceci :

foreach ($matches as $match)
{
    $gender = $match[1];
    // ...
}

preg_replace_callback

Et c'est ce que preg_replace_callback est comme. Il appelle le callback pour chaque série de correspondances (c'est-à-dire incluant tous ses groupes de capture en une seule fois), comme si vous utilisiez l'application PREG_SET_ORDER drapeau. C'est-à-dire qu'il faut contraster la façon dont preg_replace_callback est utilisé,

preg_replace_callback($pattern, $subject, 'my_callback');
function my_callback($matches)
{
    $gender = $match[1];
    // ...
    return $gender;
}

à la PREG_SET_ORDER exemple. Notez comment les deux exemples itèrent à travers les correspondances exactement de la même manière, la seule différence étant que preg_replace_callback vous donne l'occasion de renvoyer une valeur de remplacement.

3voto

mario Points 76989

Elle ne transmet pas toutes les correspondances, mais invoque la fonction de rappel pour chaque correspondance. Le callback ne recevra pas un seul paramètre de chaîne, mais une liste de chaînes. $match[0] est l'ensemble du match, et $match[1] le premier groupe de capture (ce qui se trouve dans votre regex entre les premières parenthèses).

Voici donc à quoi devrait ressembler votre rappel :

function o99_simple_callback($match){
    $url = $match[1];
    //$url = esc_url_raw( $link );
    $url_name = parse_url($url); 
    $url_name = $description = $url_name['host'];// get rid of http://..
    $url = 'http://something' .  urlencode($url)   . '?w=' . $width ; 
    return $url; // what i really need to replace 
}

Veuillez également consulter les exemples du manuel sur preg_replace_callback

2voto

steve sun Points 37

preg_replace_callback

  1. Utilisation de preg_replace_callback() pour remplacer des modèles
  2. Générer des chaînes de remplacement avec une fonction de rappel
  3. Générer des chaînes de remplacement avec une fonction anonyme

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