Jump to content

Filter number from string, except when between curly braces


Recommended Posts

Consider the following string

 

$text = "Dat foo 13.45 and $600 bar {baz:70} and {8}";

 

I need to label all numbers in $text, except for when they are between curly braces. I now have this:

 

preg_replace("/(?<!{)([0-9]+(?:\.[0-9]+)?)(?!})/","{NUMBER:$0}",$text);

 

which outputs:

 

Dat foo {NUMBER:13.45} and $ {NUMBER:600} bar {baz: {NUMBER:7} 0} and {8}

 

However, the desired output is:

 

Dat foo {NUMBER:13.45} and ${NUMBER:600} bar {baz:70} and {8}

 

where numbers between { and } are ignored, even if they are surrounded by alfanumerical (or other) characters. In other words - how do I need to adjust the regex to completely ignore whatever there is between curly braces? Your help would be greatly appreciated!

okay I have cooked something up for you:

 

echo preg_replace("~(?<![a-z{:])([0-9.]++)(?![a-z}])~i","{NUMBER: $1}","Dat foo 13.45 and $600 bar {baz:70} and {8}");

 

output:

Dat foo {NUMBER: 13.45} and ${NUMBER: 600} bar {baz:70} and {8}

 

I optimized your code a little and tweaked it a bit based on the specifications in your post. I believe the main issue with your pattern is that the negative lookbehind would allow any other character other than an opening curly brace "{" to preced it. so things like {teststring90test} would pass. Since you had the negative lookahead disallowing  the number to be follwed by a closing curly brace, the regex had no choice but to only match the 7 in {baz:70} since it could not match the 70 which it wanted to.

AyKay47, your solution is not "based on the specifications in your post".  Give it a go with {:70:}

 

The OP said "numbers between { and } are ignored, even if they are surrounded by alfanumerical (or other) characters."

AyKay47, your solution is not "based on the specifications in your post".  Give it a go with [samp]{:70:}[/samp]

 

The OP said "numbers between { and } are ignored, even if they are surrounded by alfanumerical (or other) characters."

 

thanks salathe, I was in a hurry to get out the door before I put this together so I did not have time to thoroughly test it, I appreciate you pointing out the hole in the pattern. I have revised the pattern and also made it a bit simpler, but more powerful.

 

$pattern = "~([\d.]+)(?![^{]*})~";

 

this will match any digit along with a decimal as long as it finds an opening bracket before it finds a closing bracket.

I disagree

 

{:70{}}

 

Repeating the OP for clarity: "I need to adjust the regex to completely ignore whatever there is between curly braces".

 

i had thought of that, but im not going to assume that there can be nested curly braces, since I am assuming that this is a pre-formatted string. That is what he is getting until I am notified otherwise by the OP...  :qft:

Wow, a fun little regex puzzle.

I do see both of you guys' points. :D

 

From an overall "web forum contribution ethos" standpoint, I confess that I'd approach the question like Aykay... Trying to keep it simple first before pulling out the big guns... But everyone is different, as can be seen by the difference in style and depth of responses on this very forum.

 

For my own taste in regex, I found Aykay's solution elegant and relatively lightweight. (But taste is a personal matter.)

If you wanted to kick yourself in the shins and go "all the way" just for the hell of it, that would be a bit of a mission, wouldn't it?

Without fully exploring the question, I imagine that I'd have to cut the string into chunks, using a recursive pattern to identify (and leave out) the bits with curly braces.

 

Thanks for the chance to rave about the choices we make when we answer questions. When the OP disappears, as often happens, it can feel like speaking in the dark... Unless someone else from the forum chimes in. Which happens all the time, and I appreciate that. (Thanks guys.)

 

Wishing you all a fun day

 

:)

 

 

Hi AyKay, hi Salathe,

 

Just because I have nothing better to do before breakfast this morning and I love regex puzzles, here is an answer that addresses nesting.

 

Input:

Replace 37.2 or $10 not {5} nor {a 6} nor {{7}} nor {an {8} or {{9}}!} but {unbalanced 10

 

Code:

<?php
$string='Replace 37.2 or $10 not {5} nor {a 6} nor {{7}} nor {an {8} or {{9}}!} but {unbalanced 10';
$regex=',([^{]++)({(?[^{}]*+)(??-2)(?-1))*)})?,';
echo preg_replace_callback($regex,'call_me',$string);
function call_me ($m) {
$cleaned=preg_replace(',\d+(?:\.\d+)?,','{NUMBER:\0}',$m[1]);
$donttouch=isset($m[2])?$m[2]:''; 
return $cleaned.$donttouch;
}
?>

 

Output:

Replace {NUMBER:37.2} or ${NUMBER:10} not {5} nor {a 6} nor {{7}} nor {an {8} or {{9}}!} but {unbalanced {NUMBER:10}

 

A note for regex lovers: the recursive part of the expression is home-made, rather than the one everyone copies from Jeffrey's book. In my benchmarks, it matches about 20 percent faster, but fails about twenty percent slower.

 

For my taste Aykay's solution is still a perfect answer until the OP gives signs of life. An expression like the one in this post is a mixed blessing: it works, but it's hard to explain, and even harder to maintain if the person who receives it doesn't fully understand it.

 

Wishing you all a beautiful day!

 

When the OP disappears, as often happens, it can feel like speaking in the dark... Unless someone else from the forum chimes in. Which happens all the time, and I appreciate that.

 

On the other hand, sometimes the silence can be quite deep. ;)

 

 

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.