0

I have strings like this

Foo(2)moreFoo (1)
Foo(1)moreFoo (2)
Foo(99)moreFoo (3)
Foo(99)moreFoo (9)
Foo

I need to take each string, and change the last (number)

So, in this case, I would like to get for each string:

Foo(2)moreFoo (2)
Foo(1)moreFoo (3)
Foo(99)moreFoo (4)
Foo(99)moreFoo (10)
Foo(1)

It would be like get the string, get the last occurence of (number), and replace it by (number +1)

How can I do this?

I've checked this answer, but not sure how to change it.

I've started with

$subject = 'Foo (2)(1)';

if(preg_match('\([0-9]+\)', $subject))
{   
    $pos = strrpos($subject, '\([0-9]+\)');

    if($pos !== false)
    {
        $subject = substr_replace($subject, $replace, $pos, strlen($search));
    }
}

but the problem is that could be that the number will be (10) so, I cannot just get the last 3 characters.

The (number), if exists, will be at end. It could be at middle, but the interesting one is in the end.

Community
  • 1
  • 1
Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82

2 Answers2

1

You can use preg_replace_callback() to target the individual matches and replace them:

echo preg_replace_callback('/\((\d+)\)$/m', function($match) {
    return '(' . ++$match[1] . ')';
}, $subject);

The pattern matches a parenthesized number at the end of each line and calls the anonymous function to perform the replacement. It uses $ combined with the /m modifier to match the end of each line.

Matching lines that don't have any (number) you need a somewhat trickier expression:

echo preg_replace_callback('/(?:\((\d+)\)|([^)]))$/m', function($match) {
    return isset($match[2]) ? "{$match[2]}(1)" : '(' . ++$match[1] . ')';
}, $subject);

The alternation matches either a (number) or something that's not a ) at the end of the line. If the line didn't end with ) we should add (1).

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • wow. Amazing !! Exactly what I need !! Just to improve the answer, I changed the index of $match to `$match[count($match) - 1]`. This is because we also have to consider cases like `Foo(1)(2)(3)` and get `Foo(1)(2)(4)`. Anyway I didn't specify in the question. Thank you so much! – Gonzalo.- Sep 11 '13 at 02:28
  • 1
    @Gonzalo.- My code should already do that properly, because it only matches the last one. In fact, `$match` always has two array items. – Ja͢ck Sep 11 '13 at 02:29
  • you're right. I though that it will return all the matches. Thanks – Gonzalo.- Sep 11 '13 at 02:32
  • @Gonzalo.- Btw, the last line of your input doesn't have a `(number)` at the end; should it add `(1)` if there's none? – Ja͢ck Sep 11 '13 at 02:35
  • yes I already did it on my own, but add it in the answer. Just an if, I guess – Gonzalo.- Sep 11 '13 at 02:43
0

You'll use preg_match_all() instead of preg_match() since we want the last match. This will get you ready to use a function like you mentioned, but you'll still need to strip the parens and add 1.

$subject = 'Foo (2)(1)';

echo $subject,"<br />";

if(preg_match_all('/\([0-9]+\)/', $subject, $matches))
{   
    $last_match =  $matches[0][count($matches[0])-1];
    $pos = strrpos($subject, $last_match);

    echo $pos;
    if($pos !== false)
    {
        $subject = substr_replace($subject, $replace, $pos, strlen($search));
    }
}
Chris Rasco
  • 2,713
  • 1
  • 18
  • 22