letssee has asked for the wisdom of the Perl Monks concerning the following question:

I have long lines of the format
name1=value1 name2=value2 ...
Problem is, the notation of value is not consistent. It can be scientific, decimal or can use m,M,p etc. I need them to be consistent for later use. This is what I did
sub exp { #Change all numbers in string to exponental #string has name=value pairs my ($string) = @_; for ($string) { s/\dT\s/e12/g; s/\dG\s/e9/g; s/\dM\s/e6/g; s/\dK\s/e3/g; s/\dm\s/e-3/g; s/\du\s/e-6/g; s/\dp\s/e-12/g; s/\df\s/e-15/g; s/\dn\s/e-9/g; s/=(\S+)\s/sprintf("=%e ",$1)/e; } return ($string); }
I am wondering if there is a better way to do the operation. It seems wasteful that I read the string again and again for each search and replace.

Replies are listed 'Best First'.
Re: Doing multiple search and replace operations on a string
by toolic (Bishop) on Feb 20, 2014 at 21:47 UTC
    You could use a has, something like:
    my %exponent = ( T => 12, G => 9 , M => 6 , k => 3 , p => -12, n => -9, u => -6, m => -3, ); s/\d(\w)\s/exists $exponent{$1} ? 'e' . $exponent{$1} : '' /ge;

      The (\w) will match and capture a digit which doesn't exist in the hash so will be lost in the substitution. Without a look-behind you will also consume and lose the digit before. Better I think to use a character class along with the look-behind.

      $ perl -E ' $val = q{2.73M}; %exp = ( M => 6 ); $val =~ s/\d(\w)/exists $exp{ $1 } ? q{e} . $exp{ $1 } : q{} /e; say $val;' 2.M $ perl -E ' $val = q{2.73M}; %exp = ( M => 6 ); $val =~ s/(?<=\d)(\w)/exists $exp{ $1 } ? q{e} . $exp{ $1 } : q{} /e; say $val;' 2.7M $ perl -E ' $val = q{2.73M}; %exp = ( M => 6 ); $val =~ s/(?<=\d)([TGMkmunp])/exists $exp{ $1 } ? q{e} . $exp{ $1 } : +q{} /e; say $val;' 2.73e6 ~ $

      I hope this is of interest.

      Cheers,

      JohnGG

        Thanks for the suggestion. I will try this out.
Re: Doing multiple search and replace operations on a string
by Laurent_R (Canon) on Feb 20, 2014 at 21:50 UTC

    We would really need to see a data sample to know and figure out. In general, using regexes for manipulating numbers is not a very good idea (except of course just picking up the number in a string), but there can be many exceptions, especially when reading from a file. In general, if the numbers can be read as a number by Perl straight out of the box, you probably want to let Perl convert it into a number and then apply your sprintf format to all of them. But, then, again, there can be exceptions, so please show a smple of your data.

    Update: Hum, just reading your post again just immediately after having posted, I realize that I had not understood that your letters referred to the metric system prefixes. Forget what I wrote above, it is most probably irrelevant to your problem. Sorry for having misread your problem.