开发者

Simple incremental string replace in php

I have the folow开发者_开发技巧ing code:

<?php
$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo incremental_replace($subject);
// i want the folowing: 
// Replace ? question mark in brackets [1 with 2 incremental 34]? digits

I want all the ? in the brackets to be replaced. Also, the number and position of ? can change.

How do i do that with php ? I think this can be done with preg_replace, but i don't know how.


if brackets are not nested, then the following would be enough

echo preg_replace('~\?(?=[^\[\]]*\])~e', '++$n', $subject);

otherwise use a parser:

$subject = "Replace ? question mark in [nested ? brackets] [? with ? [incremental ? [?]] ??]? digits";
$result = '';

$bc = $n = 0;
foreach(str_split($subject) as $c) {
    if($c == '[') $bc++;
    if($c == ']') $bc--;
    if($c == '?' && $bc) $c = ++$n;
    $result .= $c;
}

echo $result;

A regular expression for nested brackets is possible but will be too long and messed up.


Note by OP: If the replacements are not incremental digits but an array, you can do the folowing:

$n = 0;
$rep = array('foo', 'bar', 'baz', 'qux', 'quux');
echo preg_replace('~\?(?=[^\[\]]*\])~e', '$rep[$n++]', $subject);


Correct solution to the problem

function incremental_replace($subject) {
    $replacer = function($matches) {
        $index = 0;
        return preg_replace('/\?/e', '++$index', $matches[0]);
    };
    return preg_replace_callback('/\[[^\]]*\]/', $replacer, $subject);
}

$subject = "Replace ? question mark in brackets [? with ? incre?mental ??]?...";
echo incremental_replace($subject);

Previous form of this answer

I had misunderstood the question, and answered another similar question instead. I 'm leaving the answer here because someone might find it useful.

The general idea is this:

function replacer($matches) {
    $replacements = array(1, 2, 34);
    $index = 0;
    return preg_replace('/\?+/e', '$replacements[$index++]', $matches[0]);
}

$subject = "Replace ? question mark in brackets [? with ? incremental ??]?...";
echo preg_replace_callback('/\[[^\]]*\]/', 'replacer', $subject);

See the basic concept in action.

If you are using PHP >= 5.3, you can then do a much more generalized solution:

function incremental_replace($subject, $replacements) {
    $replacer = function($matches) use ($replacements) {
        $index = 0;
        return preg_replace('/\?+/e', '$replacements[$index++]', $matches[0]);
    };
    return preg_replace_callback('/\[[^\]]*\]/', $replacer, $subject);
}


$subject = "Replace ? question mark in brackets [? with ? incremental ??]?...";
echo incremental_replace($subject, array(1, 2, 34));

Finally, if you are willing to limit yourself to only single question marks (i.e. if the ?? inside the brackets can be changed to simply ?) then you can swap the preg_replace inside the "replacer" function with a simple str_replace, which would be faster.


A simple parser can do the job. It's just a simple solution with room for improvement. But perhaps preg_replace() or preg_replace_callback() might be more efficient in this case.

function incremental_replace($subject) {
    $inBracket  = 0;
    $length = strlen($subject);
    $count      = 0;
    $result = '';
    for ($i = 0; $i < $length; $i++) {
        $char = $subject[$i];
        switch ($char) {
            case '[':
                $inBracket++;
                break;
            case ']':
                $inBracket--;
                break;
            case '?':
                if ($inBracket > 0) {
                    $char = ++$count;
                }
                break;
        }
        $result .= $char;
    }
    return $result;
}

$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo incremental_replace($subject);
// Replace ? question mark in brackets [1 with 2 incremental 34]? digits


function replaceThem($matches){
    $i = 1;
    while ($pos = strpos($matches[0], '?'))
        $matches[0][$pos] = $i++;
    return $matches[0];
}
$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo preg_replace_callback('/\[[^\]]+\]/', 'replaceThem', $subject);

http://www.ideone.com/kBnMK


Maybe it's best to loop through the characters of the string. If you pass the opening bracket, replace the question marks you encounter with the counter, same for the second, etc. and if you pass the closing bracket...stop replacing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜