Regular expression, split string by capital letter but ignore TLA

Viewed 24133

I'm using the regex

System.Text.RegularExpressions.Regex.Replace(stringToSplit, "([A-Z])", " $1").Trim()

to split strings by capital letter, for example:

'MyNameIsSimon' becomes 'My Name Is Simon'

I find this incredibly useful when working with enumerations. What I would like to do is change it slightly so that strings are only split if the next letter is a lowercase letter, for example:

'USAToday' would become 'USA Today'

Can this be done?

EDIT: Thanks to all for responding. I may not have entirely thought this through, in some cases 'A' and 'I' would need to be ignored but this is not possible (at least not in a meaningful way). In my case though the answers below do what I need. Thanks!

7 Answers
((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))

or its Unicode-aware cousin

((?<=\p{Ll})\p{Lu}|\p{Lu}(?=\p{Ll}))

when replaced globally with

" $1"

handles

TodayILiveInTheUSAWithSimon
USAToday
IAmSOOOBored

yielding

 Today I Live In The USA With Simon
USA Today
I Am SOOO Bored

In a second step you'd have to trim the string.

any uppercase character that is not followed by an uppercase character:

Replace(string, "([A-Z])(?![A-Z])", " $1")

Edit:

I just noticed that you're using this for enumerations. I really do not encourage using string representations of enumerations like this, and the problems at hand is a good reason why. Have a look at this instead: http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html

I hope this will help you regarding splitting a string by its capital letters and much more. You can try using Humanizer, which is a free nuget package. This will save you for more trouble with letters, sentences, numbers, quantities and much more in many languages. Check out this at: https://www.nuget.org/packages/Humanizer/

You might think about changing the enumerations; MS coding guidelines suggest Pascal casing acronyms as though they were words; XmlDocument, HtmlWriter, etc. Two-letter acryonyms don't follow this rule, though; System.IO.

So you should be using UsaToday, and your problem will disappear.

Tomalak's expression worked for me, but not with the built-in Replace function. Regex.Replace(), however, did work.

For i As Integer = 0 To names.Length - 1
  'Worked
  names(i) = Regex.Replace(names(i), "((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", " $1").TrimStart()

  ' Didn't work
  'names(i) = Replace(names(i), "([A-Z])(?=[a-z])|(?<=[a-z])([A-Z])", " $1").TrimStart()
Next

BTW, I'm using this to split the words in enumeration names for display in the UI and it works beautifully.

Related