[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [FWP] subexpr nearest the 'middle' of expr



Jacob Carpenter wrote:
> 
> Let's see a subroutine that takes three (3) arguments [expr, subexpr,
> replacement] -- call them whatever you like in the actual sub -- and returns
> "expr" with the "subexpr" nearest the middle (currently, I intend 'middle'
> to mean the byte position closest to half-the-byte-length of the string)
> replaced with "replacement". Subexpr should be a literal string. and should
> be centered on the middle, not begin in the middle -- i.e.
> &replace_mid('aaaaa', 'aaa', 'BBB') is to return 'aBBBa' not 'aaBBB'.

This was my solution last time this came up for splitting a string into
two mostly equal parts on space.

    $str =~ s/ (??{"(?!.* .{$-[0]})"})/\n/s;

For your more general case you (but assuming you mean string everywhere
you say expr) this becomes

    sub replace_mid {
        use v5.6;
        use re 'eval';
        local our ($_, $s, $r) = @_;
        $s = "\Q$s";
        s/$s(??{"(?!.*$s.{$-[0]})"})/$r/s;
        return $_;
    }

Visibility of lexicals inside (??{}) is broken in 5.6 so I'm using
package variables.  This is fixed in devel perls I think.

You can eliminate "use re 'eval'" if you use qr like this

    my $re = qr/(??{"(?!.*$s.{$-[0]})"})/s;
    s/$s$re/$r/;
    
Oops, just noticed that /s does not get through to (?!.etc).  I'm pretty
sure that is not fixed in newer versions.  Should it be?  Will report to
perlbug tomorrow either way since it isn't clearly documented.  

Anyway, to make it work properly with newlines,

    my $re = qr/(??{"(?s:(?!.*$s.{$-[0]})"}))/;
    s/$s$re/$r/;

-- 
Rick Delaney
rick.delaney@home.com

==== Want to unsubscribe from Fun With Perl?  Well, if you insist...
==== Send email to <fwp-request@technofile.org> with message _body_
====   unsubscribe