One way to do this using Mathematica's native string patterns is like this:
StringReplace["aaabccccc",
xs:((x:WordCharacter)..) :> StringPadRight[x, StringLength@xs, "x"] ]
(* "axxbcxxxx" *)
Here is the same replacement expressed using a RegularExpression
:
StringReplace["aaabccccc",
RegularExpression["((\\w)\\2+)"] :> StringPadRight["$2", StringLength@"$1", "x"] ]
(* "axxbcxxxx" *)
It is possible to perform this transformation using a simple regular expression without callbacks -- but only if we reverse the string first (and unreverse the result afterwards):
StringReplace[StringReverse @ "aaabccccc",
RegularExpression["(\\w)(?=\\1)"] -> "x" ] // StringReverse
(* "axxbcxxxx" *)
The reversal is necessary due to restrictions in the use of look-behind regular expressions:
(* caution: should theoretically work, but doesn't in practice *)
StringReplace["aaabccccc", RegularExpression["(\\w)(?<=\\1\\1)"] -> "x"]
(* RegularExpression::msg25: Lookbehind assertion is not fixed length... *)
The PCRE regular expression engine used by Mathematica neither allows variable-length look-behind assertions nor detects that the look-behind in this case is actually of fixed length. By reversing the string we are able to convert the look-behind assertion into a look-ahead, which is not subject to these limitations.
StringPadRight
StringPadRight
was introduced in version 10.1 of Mathematica. In earlier versions, we can define our own:
stringPadRight[s_String, n_Integer, p_String] :=
PadRight[ToCharacterCode@s, n, ToCharacterCode@p] // FromCharacterCode
StringReplace["aaabccccc", y : Repeated[x_] :> x <> StringJoin[ConstantArray["x", StringLength@y - 1]]]
... – ciao Aug 22 at 8:25