0

I have the folowing 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.

2
  • How would you know which question marks to replace and which to leave alone? Commented Sep 7, 2011 at 7:55
  • look on this ideone.com/B8i4o Commented Sep 7, 2011 at 7:58

5 Answers 5

3

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);
Sign up to request clarification or add additional context in comments.

2 Comments

Where can i find documentation about the '++$n' ?
See pattern modifiers. So you can do $n = 42; before preg_replace and i will replace with 43, 44 and so on...
2

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.

6 Comments

Unfortunately, I am not willing to change the $subject
@pinouchon: I just realized I had answered a slightly different question instead of the one you asked. Please take a look at the new update.
@stereofrog Warning: vsprintf(): Too few arguments. Good point.
@stereofrog: Depends on whether you 'd prefer a shorter or a faster solution. Is there anything else wrong with this mess?
@stereofrog: Corrected the solution for this case, thanks for pointing it out.
|
1

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

Comments

1
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

Comments

0

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.

2 Comments

I tought about that, but I don't like it. I'm sure there is a simple way with a php built'in function.
Well...there sure is a way, but I doubt it to be simple. My guess would be that you will end up using Regular Expressions than.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.