10
$\begingroup$

Is there a way to turn AbcDefGhi into Abc Def Ghi by using StringReplace? The following pattern does not work:

StringReplace[
    "AbcDefGhi",
    (s__) ~~ (t_?UpperCaseQ) ~~ (u_) :> (s <> " " <> t <> u)
]

(* Out: AbcDef Ghi *)

Nor do close friends of that pattern that I have tried.

I can do it with a recursive function, but I feel it should be possible with StringReplace as well.

$\endgroup$
1
  • $\begingroup$ What would you want the output for a string like ""AbcDefGHij"" to be? $\endgroup$
    – Jason B.
    Commented May 9, 2018 at 19:09

5 Answers 5

6
$\begingroup$

If you wrap your before and after patterns with Shortest, it gets what you want,

sr = 
  StringReplace[
   Except[StartOfString, Shortest[(s___)]] ~~ (t_?UpperCaseQ) ~~ 
     Shortest[(u___)] :> (s <> " " <> t <> u)];
sr /@ {"DistrictOfColumbia", "AbcDefGHij"}
(* {"District Of Columbia", "Abc Def G Hij"} *)
$\endgroup$
2
  • $\begingroup$ Thanks for letting me know about Shortest! Your solution certainly works for AbcDefGhi, but not for DistrictOfColumbia. Any idea what is going on? $\endgroup$ Commented May 9, 2018 at 19:20
  • $\begingroup$ So in that case, the "f" in "Of" is matching as the lowercase letter after an uppercase letter. Therefore it won't also match as the lowercase letter before "Columbia". The key now is to use s___ instead of s__ $\endgroup$
    – Jason B.
    Commented May 9, 2018 at 19:32
9
$\begingroup$

Simply use the pattern Except[WordBoundary, t_?UpperCaseQ] as the pattern to be replaced:

sR = StringReplace[Except[WordBoundary, t_?UpperCaseQ] :> " " <> t];

sR["AbcDefGhi"]

"Abc Def Ghi"

sR["DistrictOfColumbia"]

"District Of Columbia"

sR["A B C"]
"A B C"
$\endgroup$
3
  • $\begingroup$ When I execute your code with the third example, I get double spaces... $\endgroup$ Commented May 9, 2018 at 20:00
  • $\begingroup$ @Henrik, changing StartOfString to WordBoundary seems to fix the issue. $\endgroup$
    – kglr
    Commented May 9, 2018 at 20:17
  • 1
    $\begingroup$ @HenrikSchumacher and kglr I ignored it too but OP didn't ask about anything more than LetterCharacter.. $\endgroup$
    – Kuba
    Commented May 9, 2018 at 20:18
8
$\begingroup$

What about?:

StringTrim @ StringReplace["AbcDefGhi", t_?UpperCaseQ :> " " <> t]
$\endgroup$
7
$\begingroup$

How about using StringSplit in combination with Riffle?

f[x_String] := StringJoin[Riffle[StringSplit[x, s_?UpperCaseQ :> s], {"", " "}]];

f["AbcDefGhi"]
f["DistrictOfColumbia"]

"Abc Def Ghi"

"District Of Columbia"

Unfortunately, it also does

f["A B C"]

"A B C"

So maybe this comes closer to your requirements:

g = StringReplace[
   RuleDelayed[
    Repeated[s : Except[WhitespaceCharacter]] ~~ (t__?UpperCaseQ),
    StringRiffle[Join[{s}, Characters[t]]]
    ]
   ];
g["AbcDefGhiAAA"]
g["DistrictOfColumbia"]

g["AbcDefGhi"]
g["DistrictOfColumbia"]
g["A B C"]

""Abc Def Ghi A A A""

"District Of Columbia"

"A B C"

Note that without s : Except[WhitespaceCharacter], the latter would have been "A B C".

$\endgroup$
3
  • $\begingroup$ This certainly returns the correct result too. I was just curious about doing it purely with StringReplace. $\endgroup$ Commented May 9, 2018 at 19:35
  • $\begingroup$ By the way, your g[x_] function fits my criteria and is even simpler. $\endgroup$ Commented May 9, 2018 at 19:39
  • $\begingroup$ @Shredderroy, it's often a good idea to wait before accepting an answer. Feel free to change your accepted answer if you would like to. $\endgroup$
    – Jason B.
    Commented May 9, 2018 at 20:03
1
$\begingroup$

Here is a solution that uses RegularExpression to match any upper case letter that is preceded by a non-whitespace character:

f = StringReplace[RegularExpression["(?<=\\S)(\\p{Lu})"] :> " $1"];

So then:

{"AbcDefGhi", "XAbcXDefXGhiXXX", "ABCDEFG", "A B C", "WithPowerComesGreatInscrutability"} //
Map[InputForm @* f] //
Column

(*
  "Abc Def Ghi"
  "X Abc X Def X Ghi X X X"
  "A B C D E F G"
  "A B C"
  "With Power Comes Great Inscrutability"
*)
$\endgroup$
1
  • 1
    $\begingroup$ I think that WL string patterns could use some LookAhead and LookBehind operators. $\endgroup$
    – WReach
    Commented May 10, 2018 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.