Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Regex help

by snacktime (Sexton)
on Jun 02, 2005 at 17:26 UTC ( #462974=perlquestion: print w/replies, xml ) Need Help??
snacktime has asked for the wisdom of the Perl Monks concerning the following question:

I think there is a better way of doing this, but I couldn't think of it. I have a string where I need to rewrite each occurence of [string] with the following:

__[username]__[string]__

There can be multiple instances of [string] in a line, and I don't want to match [string] a second time once it's been rewritten.

Here is what I am doing now. I know there has got to be a better way, but this does work.

my $prefix = "__" . $self->{user} . "__"; my $suffix = "__"; my %hash; my $c =0; my @contexts = sort {length $b <=> length $a} @list; foreach my $context (@contexts) { if($var_val =~s/($context?)/\@\@$c\@\@/g) { $hash{$c} = "$prefix$1$suffix"; $c++; } } foreach my $key (keys %hash) { $var_val =~s/\@\@$key\@\@/$hash{$key}/g; }

Replies are listed 'Best First'.
Re: Regex help
by Roy Johnson (Monsignor) on Jun 02, 2005 at 17:45 UTC
    So you've got multiple possible strings, and some of them might be substrings of others of them? If you combine them into one alternation, longest first, you should be ok:
    my $super_regex = join '|', sort {length $b <=> length $a} map quoteme +ta($_), @list; $var_val =~ s/($super_regex)/$prefix$1$suffix/g;
    Regexp::Optimizer might be of use if @list is long.

    Update: added quotemeta as per ikegami's note.


    Caution: Contents may have been coded under pressure.
      Ah that's exactly what I was looking for. Sorry for not explaining the issue correctly in my first post. Some of the strings being substrings of others was the real issue as you guessed.
Re: Regex help
by ikegami (Pope) on Jun 02, 2005 at 17:41 UTC

    s///g won't search replaced text, as shown in the following snippet:

    $search_for = '[string]'; $user = '[user]'; local $_ = 'foo [string] bar [string] baz'; s/(\Q$search_for\E)/__${user}__${1}__/g; print("$_\n"); # foo __[user]__[string]__ bar __[user]__[string]__ baz

    You can use s///ge if you need to generate $user dynamically for each match.

      Silly me, I forgot what the problem was and mistated it. The problem is that the string I am searching for can exist as a substring of another element of @contexts, but I don't want it to match if it's already been rewritten.

      For example in the list I am looping through, one element could be demo-outgoing, and a later element could be demo. I don't want the string demo in the already formatted string __user__demo-outgoing__ to be matched and rewritten again.

      Does that make sense?

        So @context contains search strings? (This is why it's important to give a runable piece of code, including sample input. It takes the guessing out of the game.)

        my @contexts = qw( demo-outgoing demo ); local $_ = 'foo demo-outgoing bar'; my $regexp = join('|', map { quotemeta($_) } @contexts); s/($regexp)/__user__${1}__/g; print("$_\n"); # foo __user__demo-outgoing__ bar
Re: Regex help
by Joost (Canon) on Jun 02, 2005 at 17:44 UTC
    what's in @list? Why does your code match "@@something@@" while your explenation states "[something]"?

    how about this, assuming @strings is an array containing a list of "somethings" to replace:

    for my $string (@strings) { $input =~ s/\[\Q$string\E\]/__[username]__[$string]__/; }
    This will replace every first occurence of every string in @strings with "__[username]__[$string]__"

    update: see perlretut

Re: Regex help
by Jasper (Chaplain) on Jun 02, 2005 at 17:50 UTC
    How not to ask a question? I don't understand one thing you're trying to do.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://462974]
Approved by coreolyn
help
Chatterbox?
[LanX]: xD
[erix]: 'systematic' is going to be hard to define I think
[marto]: Err no @
LanX Much enemy much ore
[Corion]: marto: Naah, my module doesn't care, but the users of my module might expect some things to work in Chrome that only work in later builds (or, as seems to be the case, don't work there either ;) )
[Corion]: But I really wonder - I can tell Chrome to go offline, but requesting pages over the network still succeeds. But if I manually click the "offline" checkbox, that's different :-/

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (8)
As of 2017-12-12 20:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What programming language do you hate the most?




















    Results (335 votes). Check out past polls.

    Notices?