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

I am a novice seeking wisdom.
I have a string which looks like:

25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}
what I need is a regex that transforms all the spaces within the curly brackets to underscores. e.g the result should be:
25 {fred_and_barney} text 2.36 12.0 {bam_bam} text {pebbles}
is there a simple way to do this?

What would be even neater is if I could substitute the contents of the brackets with a variable. This must surely be possible!?

thanks for your help

20030422 Edit by Corion: Added formatting

novice Moritz

Replies are listed 'Best First'.
Re: looking for a regex
by BrowserUk (Patriarch) on Apr 22, 2003 at 09:40 UTC

    Assuming that the {} aren't nested.

    $s ='25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}'; $s =~ s[(\{.*?\})]{ local $_=$1; tr[ ][_]; $_}ge; print $s; 25 {fred_and_barney} text 2.36 12.0 {bam_bam} text {pebbles}

    You'll have to explain what you mean by substitute a variable.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
      Thanks. A neat trick By substituting a variable I meant:
      @sub=('men','boy','girl'); $s ='25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}';
      end result
      $s ='25 {men} text 2.36 12.0 {boy} text {girl}';
      I know I can do this by splitting, substituting and rejoining, but I though there may be a more elegant way.

        Provided you know you have enough values in @sub to match the pairs of curlies

        $s ='25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}'; $n=0; $s =~ s_\{.*?\}_{$sub[$n++]}_g; print $s; 25 {men} text 2.36 12.0 {boy} text {girl}

        I'm not at all sure about using _ as the delimiter, but everything else I tried was altogether too messy.


        Examine what is said, not who speaks.
        1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
        2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
        3) Any sufficiently advanced technology is indistinguishable from magic.
        Arthur C. Clarke.
Re: looking for a regex
by jmcnamara (Monsignor) on Apr 22, 2003 at 10:00 UTC

    Here is one way using a negated character class:
    #!/usr/bin/perl -wl use strict; my $str = '{fred and barney} {bam bam} {pebbles} {} { }'; print $str; $str =~ s|({[^}]+})|(my $tmp = $1) =~ s/ /_/g; $tmp|eg; print $str; __END__ Prints: {fred and barney} {bam bam} {pebbles} {} { } {fred_and_barney} {bam_bam} {pebbles} {} {___}
    To substitute a variable you could modify the above as follows:
    my $str2 = '{fred and barney} {bam bam} {pebbles} {} { }'; print $str2; my $var = "xxxxx"; $str2 =~ s|({[^}]+})|{$var}|g; print $str2; __END__ Prints: {fred and barney} {bam bam} {pebbles} {} { } {xxxxx} {xxxxx} {xxxxx} {} {xxxxx}

    If you have to deal with nested braces you should have a look at the Text::Balanced module.

    --
    John.

Re: looking for a regex
by broquaint (Abbot) on Apr 22, 2003 at 09:52 UTC
    Not a regex, but this seems to do the job ...
    my $str = "25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}"; print "before - $str\n"; substr($str, pos($str) - length($1), length $1) =~ s/ /_/g while $str =~ /\G .*? { ( [^}]+ ) } /xg; print "after - $str\n"; __output__ before - 25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles} after - 25 {fred_and_barney} text 2.36 12.0 {bam_bam} text {pebbles}
    Substituting bracket contents with a variable is somewhat simpler
    my $str = "25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles}"; print "before - $str\n"; $str =~ s/{ ([^}]+) }/{$rep}/xg; print "after - $str\n"; __output__ before - 25 {fred and barney} text 2.36 12.0 {bam bam} text {pebbles} after - 25 {between brackets} text 2.36 12.0 {between brackets} text +{between brackets}
    See. perlre for more info on regular expressions in perl.
    HTH

    _________
    broquaint

Re: looking for a regex
by perlguy (Deacon) on Apr 22, 2003 at 14:44 UTC

    Here's a quick way, though I haven't tested every possible scenario:

    $string =~ s/ (?=[^{}]*})/_/g;

    Update: Added } to the negated character class to prevent backtracking during the greedy * operation.

    I'm still working on the variable substitution...

    And here it is (similar to others):

    my @sub = qw(men boy girl); $string =~ s/(?<={)[^}]*(?=})/shift @sub/ge;