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$
  • $\begingroup$ What would you want the output for a string like ""AbcDefGHij"" to be? $\endgroup$ – Jason B. May 9 '18 at 19:09
5
$\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$
  • $\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$ – Shredderroy May 9 '18 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. May 9 '18 at 19:32
8
$\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$
  • $\begingroup$ When I execute your code with the third example, I get double spaces... $\endgroup$ – Henrik Schumacher May 9 '18 at 20:00
  • $\begingroup$ @Henrik, changing StartOfString to WordBoundary seems to fix the issue. $\endgroup$ – kglr May 9 '18 at 20:17
  • 1
    $\begingroup$ @HenrikSchumacher and kglr I ignored it too but OP didn't ask about anything more than LetterCharacter.. $\endgroup$ – Kuba May 9 '18 at 20:18
7
$\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$
  • $\begingroup$ This certainly returns the correct result too. I was just curious about doing it purely with StringReplace. $\endgroup$ – Shredderroy May 9 '18 at 19:35
  • $\begingroup$ By the way, your g[x_] function fits my criteria and is even simpler. $\endgroup$ – Shredderroy May 9 '18 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. May 9 '18 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$
  • $\begingroup$ I think that WL string patterns could use some LookAhead and LookBehind operators. $\endgroup$ – WReach May 10 '18 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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