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

I am trying to substitute all my mail addresses in on my html pages from this:
@mail.ab.com
To this:
_n@mail.ab.com
So if there was an email address of smith@mail.ab.com then it would be smith_n@mail.ab.com. I tried:
s/\@mail.ab.com/_n\@mail.ab.com/gi;
The result is most of the time it changes it to:
smith_n_n_n_n_n_n@mail.ab.com
Please help.

Replies are listed 'Best First'.
Re: Substitute problem
by sauoq (Abbot) on Jul 30, 2003 at 21:05 UTC

    Uhm... the line you gave will work. I expect you are inadvertently running it on a single page more than once. You could modify the regex to prepend the "_n" only if those two chars aren't already "_n" by using a negative look-behind assertion:

    s/(?<!_n)\@mail.ab.com/_n\@mail.ab.com/gi;

    -sauoq
    "My two cents aren't worth a dime.";
    
      Thanks, I am running it in 1000's of files using File::Find.
        If you got multiple "_n" appendages in one run, this might have happened because File::Find was somehow following "links" (in unix, there are "symbolic links" and "hard links"; I think the comparable notion in MS-Windows is called "shortcuts") -- i.e. shortcuts/links may exist in your directory structure, such that there is more than one path to a single data file or directory, and File::Find would pursue all of them, and hit on some (sets of) files more than once.
Re: Substitute problem
by BrowserUk (Patriarch) on Jul 30, 2003 at 21:12 UTC

    Try

    s/(?<!_n)\@mail\.ab\.com/_n\@mail.ab.com/g;

    The zero-width negative look-behind, (?<!_n) says only match if the @ sign is NOT preceded by the _n. Ie. if the address already has the '_n' it won't be modified.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller

      Thanks to both of you!!!!

      You saved me hours (and probably days) of figuring this out! It works as it should on NT and my next step is to do it on my Unix and I assume it will work there also.

      The ?<!data is a reg expression that says dont match any of the data word? So I assume the ?< is a predecessor reg expression and the ! is the not part of the reg expression?

        Right. Sort of:)

        (?<!  ) is the negative look-behind assertion construct. You put the bit that you want to trigger failure in the gap, but it must be a simple, fixed width expression. You can't use a variable width thing in there.

        See perlre. Section Extended patterns for more information. (Theres actually not much more info there. See perlretut. Section "Looking ahead and looking behind" which does.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller