2

I like to replace the letters "KELLY" bettween "#" with the same length of "#". (here, repetitive five #'s instead of 'KELLY')

$str = "####KELLY#####";   // any alpabet letters can come.
preg_replace('/(#{3,})[A-Z]+(#{3,})/', "$1$2", $str);

It returns ######### (four hashes then five hashes) without 'KELLY'.

How can I get ############## which is four original leading hashes, then replace each letter with a hash, then the five original trailing hashes?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
user1942626
  • 805
  • 1
  • 9
  • 15

2 Answers2

2

The \G continue metacharacter makes for a messier pattern, but it enables the ability to use preg_replace() instead of preg_replace_callback().

Effectively, it looks for the leading three-or-more hashes, then makes single-letter replacements until it reaches the finishing sequence of three-or-more hashes.

This technique also allows hash markers to be "shared" -- I don't actually know if this is something that is desired.

Code: (Demo)

$str = "####KELLY##### and ###ANOTHER###### not ####foo#### but: ###SHARE###MIDDLE###HASHES### ?";
echo $str . "\n";
echo preg_replace('/(?:#{3}|\G(?!^))\K[A-Z](?=[A-Z]*#{3})/', '#', $str);

Output:

####KELLY##### and ###ANOTHER###### not ####foo#### but: ###SHARE###MIDDLE###HASHES### ?
############## and ################ not ####foo#### but: ############################# ?

Breakdown:

/               #starting pattern delimiter
(?:             #start non-capturing group
  #{3}          #match three hash symbols
  |             # OR
  \G(?!^)       #continue matching, disallow matching from the start of string
)               #close non-capturing group
\K              #forget any characters matched up to this point
[A-Z]           #match a single letter
(?=             #lookahead (do not consume any characters) for...
    [A-Z]*      #zero or more letters then
    #{3}        #three or more hash symbols
)               #close the lookahead
/               #ending pattern delimiter

Or you can achieve the same result with preg_replace_callback().

Code: (Demo)

echo preg_replace_callback(
         '/#{3}\K[A-Z]+(?=#{3})/',
         function($m) {
             return str_repeat('#', strlen($m[0]));
         },
         $str
     );
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

I solved the problem with preg_replace_callback function in php. Thanks CBroe for the tips.

preg_replace_callback('/#{3,}([A-Z]+)#{3,}/i', 'replaceLetters', $str);

function replaceLetters($matches) {
    $ret = '';
    for($i=0; $i < strlen($matches[0]); $i++) {
        $ret .= "#"; 
    }
    return $ret;
}
user1942626
  • 805
  • 1
  • 9
  • 15