Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numbered occurrences for preg_replace_callback

I'm trying to figure out how to identify the order of occurrences for matched regex groups. but can't find any such functionality. Yet, I'm sure it has to be there and I'm just doing something wrong...

So far I have this:

$string = "SELECT id, title FROM table WHERE id = ?d AND qwe=?s";
$pattern = '/(\?+[sdf]{1})/i';
$data = array(111, 222, 333);
$inc = 0;

function callback($matches) {
    global $inc, $data;
    $inc++;

    switch ($matches[0]) {
        case '?s':
            return '`'.$data[$inc].'`';
        case '?d':
            return (int) $data[$inc];
        case '?f':
            return (double) $data[$inc];
    }
}
print_r(preg_replace_callback($pattern, 'callback', $string));

It works, but that thing with $inc is certainly not the way to go...

I want to avoid using $inc at all here. Is there a way to know the order of occurrences when these regex groups are matched? That's what I'm trying to do. So, maybe I will have not only the matches, but a number that will tell me what match this is in order.

Is there a better solution to this problem?

like image 410
NewProger Avatar asked May 16 '26 06:05

NewProger


1 Answers

You mix up two things: multiple matches and groups. When you have groups, you can access them (by name or by ID). When you have multiple matches (and when you use preg_replace..., you actually have the regex engine find all non-overlapping matches in the text and process them individually), the regex engine does not know if it is the first, or second, etc. So, there is no other way with the current input data than using a counter.

If you can change the input data, I suggest using a key-value $data array where keys will be equal to the variables you want to match in the text (s, f, or d). In order to access them from inside a match, you need to capture [sfd] in your regex, i.e. you need to wrap that character class with a capturing group.

Use

$string = "SELECT id, title FROM table WHERE id = ?d AND qwe=?s";
$pattern = '/\?+([sdf])/i';
$data = array("s" => 111, "d" => 222, "f" => 333);
$inc = 0;

echo preg_replace_callback($pattern, function ($matches) use ($data) {
    switch ($matches[0]) {
        case '?s':
            return '`'.$data[$matches[1]].'`';
        case '?d':
            return (int) $data[$matches[1]];
        case '?f':
            return (double) $data[$matches[1]];
    }
}, $string);

See the PHP demo.

like image 117
Wiktor Stribiżew Avatar answered May 18 '26 20:05

Wiktor Stribiżew



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!