0

I am trying to increment a counter at the end of a string in PHP. The counter is always between parenthesis at the end of the string and the rest can be literally anything, meaning there could even be something that looks like the counter (i.e. : a number between parenthesis), but has a different meaning and shouldn't be altered.

Exemples :

  1. Foo (Bar) (666) (123) : Foo (Bar) (666) is the main part and 123 is the counter. I want to get : Foo (Bar) (666) (124). (666) looks like the counter but since it isn't located at the end of the string it isn't considered as such.
  2. Lorem ipsum dolor sit amet (1337) : Lorem ipsum dolor sit amet is the main part and 1337 is the counter. I want to get : Lorem ipsum dolor sit amet (1338).

The exact implementation doesn't matter. I just would like to use a regex to match the main part and the counter so I could put them in variables, increment the counter and build back the string.

I can easily match the counter with something like \((\d*)\)$ but I can't figure out how to match the rest of the string.

What regex could do the job ?

8
  • does the Foo, Bar, and 666 part is dynamic -- can be changed with something else? Commented Jul 9, 2018 at 0:07
  • 1
    You can use preg_replace_callback. Commented Jul 9, 2018 at 0:12
  • @BagusTesa Yes they are dynamic, that's what I meant by "absolutely anything". I just gave those as exemples to show that there could be other parenthesis and numbers there. Commented Jul 9, 2018 at 1:10
  • roughly you can match them using: (\w+ \(\w+\) \(\d+\)) \(\d+\) and take the second group.. example. Commented Jul 9, 2018 at 1:19
  • @BagusTesa I'm sorry, maybe I wasn't clear enough : what I called the "main part" can be literally anything and doesn't have to follow the structure I gave. I've changed my question to make it clearer. Commented Jul 9, 2018 at 1:39

2 Answers 2

2

Well, I am not in love with this solution, but since you have asked for it:

Here is a solution using preg_replace_callback:

(?<=\()\d+(?=\)$)

Demo

Sample Code:

$re = '/(?<=\()\d+(?=\)$)/';
$str = 'Lorem ipsum dolor sit amet (1337)';

$result = preg_replace_callback(
        $re,
        function ($matches) {
            return ++$matches[0];
        },
        $str
    );
echo "The result of the substitution is ".$result;

PS: If your "string" is actually the content of a multiline file replace $ with \Z in $re to match the end of the file.

Sign up to request clarification or add additional context in comments.

3 Comments

Seems to me that the m pattern flag and $subst = '$1'; can be removed. And <?php while you are editing.
For a bit more "polish" to your answer, you could try this pattern to eliminate one of the capture groups: /\(\K\d+(?=\)$)/ because \K restarts the fullstring match. and if matching the trailing ) is not required, you could remove that component from the pattern -- but we don't actually know that detail.
@mickmackusa indeed, there are actually, many ways to match the pattern in question.
0

At the same time as the accepted answer was posted, I found a way to do it the way I pictured it at first (i.e. : matching the name and the counter in separate groups). So I figured I would post it as an answer, even though @wp78de's one is clearly better.

Other approach

I had to use a non capturing group next to the name group because the negative lookahead isn't quantifiable apparently : exemple

Comments

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.