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

Ok, I admit it... I suck at Regular Expressions. There, I said it.

After pretty much 2 pots of coffee, I still can't get it right. Therefore I come asking for wisdom...

I have a string like:

"I have a 15" latter and a 6" foot arm."

I need to change it to:

"I have a 15" latter and a 6" foot arm."

In other words I need a regular expression that will not touch the quotation marks at the start or end of the string but will change all the ones in-between.

Can anybody help me, please?

Andrew Kenton Mitchell

Replies are listed 'Best First'.
Re: Another Regular Expression
by BrowserUk (Patriarch) on Jan 08, 2005 at 18:37 UTC

    If you know (or test) that the first and last characters are quotes then you can use substr to isolate those from conversion:

    my $string = '"I have a 15" latter and a 6" foot arm."'; substr( $string, 1, -1 ) =~ s["]["]g; print $string; "I have a 15" latter and a 6" foot arm."

    Or, you can use a lookbehind and a lookahead assertion to prevent the first and last characters being touched:

    my $string = '"I have a 15" latter and a 6" foot arm."'; $string =~ s[(?<=.)"(?=.)][&quot;]g; print $string; "I have a 15&quot; latter and a 6&quot; foot arm."

    BTW. What is a '15" latter'?


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.
Re: Another Regular Expression
by gopalr (Priest) on Jan 09, 2005 at 01:54 UTC

    Hi Andrew Kenton Mitchell

    Try this

    $string = '"I have a 15" latter and a 6" foot arm."'; $string=~s#(^")(.+?)("$)#$1.Quot($2).$3#eg;

    or

    $string=~s#(^")([^\n]+)("$)#$1.Quot($2).$3#eg; sub Quot { my ($line)=@_; $line=~s#"#&quot;#g; return $line; }

    Thanks,

    Gopal.R

Re: Another Regular Expression
by Zaxo (Archbishop) on Jan 09, 2005 at 02:19 UTC

    I recommend the HTML::Entities module for that sort of job.

    $ perl -MHTML::Entities -e'print encode_entities(q(I have a 15" latter + and a 6" foot arm.))' I have a 15&quot; latter and a 6&quot; foot arm.$
    That doesn't cover omitting leading and trailing quotes, so lets cook up a regex and a substitution,
    use HTML::Entities; my $str = q("I have a 15" latter and a 6" foot arm."); my $re = qr/^("?)(.*?)("?)$/s; $str =~ s/$re/$1.encode_entities($2).$3/e; print $str, $/; __END__ "I have a 15&quot; latter and a 6&quot; foot arm."
    The regex looks for an optional initial quote, arbitrary text, and an optional final quote, capturing all three (any may be empty). The substitution is exec'ed so that we can call the convenient encode_entities function. We might have used substr, but the presence of optional elements decided in favor of substitution.

    Update: In CB, holli++ and Sidhekin++ pointed out to me that I'd overgeneralized the problem. Here is my take on the exact question asked, using substr,

    use HTML::Entities; my $str = q("I have a 15" latter and a 6" foot arm."); substr($str, 1, -1) = encode_entities substr($str, 1, -1), q("); print $str, $/; __END__ "I have a 15&quot; latter and a 6&quot; foot arm."
    That assumes the enclosing quotes are always present, and only encodes interior quotes. I also added the /s flag to the earlier substitution code so that newlines don't interfere.

    After Compline,
    Zaxo

      HTML::Entities is a good idea. here is a version that doesn´t need a regex:
      use HTML::Entities; my $str = q("I have a 15" latter and a 6" foot arm."); substr($str, 1, length($str)-2) = encode_entities(substr($str, 1, leng +th($str)-2)); print $str; #"I have a 15&quot; latter and a 6&quot; foot arm."