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

Hi monks , I have a problem I am working on a code in which I am executing a commad and depending upon the result i am performing some operations.Now my problem is that i want to substitute dot instead of underscore
my @envArray = `rsh sdp1 su - oracle8 -c env `; my $i = 0; my @array; foreach(@envArray) { if($_ =~ (/^(ORACLE_SID)\=(.*)/i)|(/(ORACLE_HST_SID)\=(.*)/i)| +(/(ORACLE_HOME)\=(.*)/i)|(/(SDP_HOME)\=(.*)/i)) { my $temp = lc($1); #$temp = s|_|.|; $array[$i] = "$temp=$2\n"; $i++; }
Now my array contains data in the form oracle_hst_sid=hsta oracle_sid=sdpa oracle_home=/oracle/product/10.2.0 sdp_home=/oracle/oracle8 I want it to contain data in the form oracle.hst.sid=hsta oracle.sid=sdpa and so on .I am tryng to reduce my steps..please help

Replies are listed 'Best First'.
Re: substitution in a string
by pjf (Curate) on Sep 28, 2005 at 08:54 UTC

    G'day s_gaurav1091

    Trying to reduce your steps? Sounds like good old fashioned perl-golf. ;) However, I'll try to give suggestions that make your code more tidy but without loss of readability.

    You can reduce your if to testing a single regular expression. The code below uses some more specific variable names, and pushes non-oracle variables onto our output array without alteration.

    my @envArray = `rsh sdp1 su - oracle8 -c env `; my @translated_env; # Rather than '@array'. foreach (@envArray) { if ( m{^( ORACLE_SID | ORACLE_HST_SID | ORACLE_HOME | SDP_HOME )=( +.*)}ix ) { # Look, an oracle variable! my ($env_key, $env_value) = ($1, $2); # $env_key rather tha +n $temp # Tweak it... $env_key = lc($env_key); $env_key =~ tr{_}{.}; # Transliterate _ to +. # And put it into our array. push(@translated_env,"$env_key=$env_value"); } else { # Otherwise leave the environment variable unharmed. push(@translated_env,$_); } }

    The code can certainly be reduced to a smaller number of steps, but I believe that maintainability is more important than clever tricks. It should be noted that the m{...}x construct allows whitespace (and comments) to be inserted without the meaning of the regexp changing. Also note that the assignment into $env_key and $env_value could be done inside the if condition, but results in a condition that I at least would consider too long.

    All the best,

Re: substitution in a string
by GrandFather (Saint) on Sep 28, 2005 at 08:41 UTC

    If I understand your problem correctly the line of code you want is @newArray = (map {tr/_/./; $_} @array):

    my @newArray = ( map {my ($lhs, $rhs) = /(.*?)=(.*)/; $lhs =~ tr/_/./; "$lhs=$rhs"} @array );
    Update: altered to only alter text to the left of = per pjf's suggestion


    Perl is Huffman encoded by design.

      This solution works a treat provided that there are no underscores as part of the environment value. Unfortunately, for many systems these are common as parts of pathnames. A variable such as oracle_home=/local_oracle/ would turn into oracle.home=/local.oracle/, which may not be desirable.

      If you were to split the keys from the values beforehand, then a map is an excellent way to perform the alterations.

      Cheerio,

Re: substitution in a string
by skillet-thief (Friar) on Sep 28, 2005 at 08:47 UTC

    Two problems with the substitution you tried:

    $temp = s|_|.|;

    First, you need a tilde: $temp =~ s///

    Second, you need the /g operator so that more than just the first "_" is replaced.

     $temp =~ s|_|.|g;
    sub sk{ return unless $in = shift; $in =~ s!(.)$!!; print $1; sk($in)} sk("gro.alubaf@yehaf");
Re: substitution in a string
by Roy Johnson (Monsignor) on Sep 28, 2005 at 12:55 UTC
    Here's an in-place edit:
    s/([^=]+)/(my $lhs=$1) =~ tr:_:.:; $lhs/e for @envArray;
    Making it work on a copy is just a matter of
    s/([^=]+)/(my $lhs=$1) =~ tr:_:.:; $lhs/e for @array=@envArray;

    Caution: Contents may have been coded under pressure.
      One problem with this - it will substitute . for _ in all environmental variables.

      How about

      /^(?i:ORACLE_SID|ORACLE_HST_SID|ORACLE_HOME|SDP_HOME)=/ && s/([^=]+)/(my $lhs=$1) =~ tr:_:.:; $lhs/e for @envArray;

      Roger

      update: better idea by Roy Johnson below. Doh!

      However his code doesn't actually work because the brackets are the (?imsx-imsx:pattern) extension. Below is a possible fix:

      s/^((?i)ORACLE_SID|ORACLE_HST_SID|ORACLE_HOME|SDP_HOME)(?==)/(my $lhs=$1) =~ tr:_:.:; $lhs/e for @envArray;

        There's really no need to do a separate match and substitution, just change the pattern that the substitution matches:
        s/^((?i:ORACLE_SID|ORACLE_HST_SID|ORACLE_HOME|SDP_HOME))(?==)/(my $lhs +=$1) =~ tr:_:.:; $lhs/e for @envArray;
        (update: corrected the missing parens, as per Roger_B's update)

        Caution: Contents may have been coded under pressure.