I'm working on learning how to use regular expressions, and have found a conversion that has me stuck.

Given the statements:

1. pi=3.14 and pie
2. pie and pi=3.14

How do I match pi and turn it in to 3.14 without also catching pie? This is user input, so I can't rely on position in the string.

My attempt was:
s/pi\W/3.14/g

That almost worked, but the \W ate the equals sign so I got:
3.143.14 and pie

Thanks in advance for any help. (This is not homework, but it is school related.)

Recommended Answers

All 3 Replies

Use this replace block: s|((?<![\w\d])pi(?![\w\d]))|3.14|g It has a negative lookbehind (?<![\w\d]) and lookahead (?![\w\d]) for characters preceeding and following the word pi. For more about lookahead/behinds:

http://www.perl.com/pub/a/2003/07/01/regexps.html


Proofs:

my ($in) = "8 * pie";
$in =~ s/((?<![\w\d])pi(?![\w\d]))/3.14/g;
#result: $in = 8 * pie
my ($in) = "epi * 7";
$in =~ s/((?<![\w\d])pi(?![\w\d]))/3.14/g;
#result: $in = epi * 7
my ($in) = "pi * 4";
$in =~ s/((?<![\w\d])pi(?![\w\d]))/3.14/g;
#result: $in = 3.14 * 4
my ($in) = "pi * 4 * epi + pi / pie";
$in =~ s/((?<![\w\d])pi(?![\w\d]))/3.14/g;
#result: $in = 3.14 * 4 * epi + 3.14 / pie

PS: You may want to do another replace for multiplication shorthand: on paper 3PI * 4 is valid math markup; but if your passing this through an eval block; 3[pi replaced] isn't going to be the same. The block I've given you will NOT replace instances like this: 3PI. but it would replace the PI in instances like this: 3 PI (the space between 3 and PI is the key here). On that capitilized note, you may want to replace the "pi" in the block with (pi|PI|pI|Pi) a-la: $in =~ s/((?<![\w\d])(pi|PI|pI|Pi)(?![\w\d]))/3.14/g; or do:

$in = lc($in); #convert characters to lowercase
$in =~ s/((?<![\w\d])pi(?![\w\d]))/3.14/g;

parsing user input for all possible syntax variations is an excersize in frustration as Matts code above shows. If you want to simply find "pi=3.14" a turn it into 3.14:

s/pi=3\.14/3.14/g;

or if 'pie=3.14' is a possibility too:

s/pie?=3\.14/3.14/g;

and last, if case sensitive matching is not wanted:

s/pie?=3\.14/3.14/ig;

Thanks for the help! I'll take apart the regexp and figure out what each part does. :-)

Implicit multiplication gets hard when you stop limiting variable names to one letter... but it's the better way to do it!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.