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

How do I find and replace every letter in a word with a modified version of the word? Basically I need to find any letter [a-zA-Z] and replace it with [aA][zZ]. For Example:

my $word = "layer" my $new_word = "[l][a][y][e][r]"

2018-07-17 Athanasius added code tags within text

Replies are listed 'Best First'.
Re: regex find and replace with a twist
by haukex (Archbishop) on Jul 17, 2018 at 05:20 UTC
    I need to find any letter [a-zA-Z] and replace it with [aA][zZ].

    I hope I got the brackets right - please use <code> tags for code everywhere, and sample data too. Anyway, unfortunately, your specification is unclear. Your example can be solved with a simple regex (s/([a-zA-Z])/[$1]/g), but I don't understand the above specification, so I don't know if this solves your problem. Please have a look at perlrequick, perlretut, and Re: How to ask better questions using Test::More and sample data, and in the future, please show the code you've tried along with your question as well.

Re: regex find and replace with a twist
by dsheroh (Monsignor) on Jul 17, 2018 at 07:26 UTC
    For this example, at least, I don't think I'd bother with a regex. Instead, I'd split the string up into individual characters, process each character, and join the results back into a string:
    my $word = 'layer'; my $new_word = join '', map { "[$_]" } split '', $word; # Or, if I want to be more explicit about the process: # my @raw_chars = split '', $word; # my @cooked_chars = map { "[$_]" } @raw_chars; # my $new_word = join '', @cooked_chars;

    Edit: As pointed out in replies, the spec was to only bracket characters in the range a-zA-Z, not all characters. This can be fixed with a minor adjustment to the map. Change it to map { $_ =~ /[a-zA-Z]/ ? "[$_]" : $_ } and you get the result:

    $ perl -E '$word = "layer123 $-.% foo"; $new_word = join "", map { $_ +=~ /[a-zA-Z]/ ? "[$_]" : $_ } split "", $word; say $new_word;' [l][a][y][e][r]123 0.% [f][o][o]

      I think a split-based solution (which I personally would not use) would have to look something like this to get what seems (I think) to be the required output:

      c:\@Work\Perl\monks>perl -wMstrict -le "my $word = '$-.%aBc&/'; my $new_word = join '', map { /[[:alpha:]]/ ? qq{[$_]} : $_ } split '', $word ; print qq{'$word' -> '$new_word'}; " '$-.%aBc&/' -> '$-.%[a][B][c]&/'
      Since this depends on two regexes, I think you might as well use a  s/// approach and be done with it.


      Give a man a fish:  <%-{-{-{-<

      what if $word = '$-.%'?

        That's simple to try .. I suspect you didn't try it.

        tab@music3:~/2018-0717$ cat pm.pl #!/usr/bin/perl use strict; use warnings; { my $word = '$-.%'; my $new_word = join ( '', map { "[$_]" } split '', $word ); print "$word -> $new_word\n"; } tab@music3:~/2018-0717$ perl pm.pl $-.% -> [$][-][.][%] tab@music3:~/2018-0717$

        Perl doesn't care what's in the string -- more specifically, split doesn't have problems with any characters that may have special meaning in a regex.

        Alex / talexb / Toronto

        Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: regex find and replace with a twist
by james28909 (Deacon) on Jul 17, 2018 at 12:16 UTC

    Heres a short example that does that:

    use strict; use warnings; my $modified_string; while ( read DATA, my $buf, 1 ) { $modified_string .= "[$buf]" unless $buf !~ /[a-zA-Z]/; } print $modified_string; __DATA__ this is a test

    And yet another example!:

    use strict; use warnings; my $string = "this is a test"; my $modified_string = $string =~ s/([a-zA-Z])/\[$1\]/gr; print $modified_string;

    EDIT: changed pattern match to include only characters a-z in first example.