2

I am trying to get a string to have an underscore '_' everywhere on a case changes in a string to make it more clear to the user. For example if we have a String 'personal IDnumber', I want to make it to 'personal_ID_number'. This is in C#.

Thank you, I appreciate any help, suggestions.

-Sid

Sid
  • 1,145
  • 5
  • 17
  • 24
  • In your case you also replaced a white space with an underscore. Is this also what you are looking for? Also, what have you tried? – npinti Jul 26 '11 at 14:19
  • white space is not an issue, I am only trying to get an underscore on every case change, I tried a split on every uppercase letter, that didn't work, now i am trying to check every char for its case and comparing its case with case of every character before and after that. Thanks – Sid Jul 26 '11 at 14:34
  • possible duplicate of [.NET - How can you split a "caps" delimited string into an array?](http://stackoverflow.com/questions/155303/net-how-can-you-split-a-caps-delimited-string-into-an-array) – GSerg Aug 22 '14 at 18:05

2 Answers2

5

Replace on a case change
You are looking for this (I removed the space before ID, assuming it a typo)

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

It will transform personalIDnumber into personal_ID_number

See it here on Regexr

the Lookbehind ((?<=[a-z])) and lookahead ((?=[A-Z])) construction is matching the empty string between a lower case and a uppercase letter (or the other way round in the second part after the pipe |) and replace this with a underscore.

Replace on a case change with optional whitespace
If you want to include whitespace in the replace, just include it between the lookarounds

(?:(?<=[a-z])\s*(?=[A-Z]))|(?:(?<=[A-Z])\s*(?=[a-z]))

It will transform personal IDnumber into personal_ID_number

See this here on Regexr

Replace on a case change, but each word starts with an uppercase
If you say every word starts with an uppercase letter, then you can do this

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

This will make from

PersonalIDNumber
JustAnotherTest
OtherWordWithID
SomeMORETest

this

Personal_ID_Number
Just_Another_Test
Other_Word_With_ID
Some_MORE_Test

See this here on Regexr

stema
  • 90,351
  • 20
  • 107
  • 135
  • Thank you stema, Ill try it and let you know. – Sid Jul 26 '11 at 14:38
  • Sorry, this works but I have another another case which fails if I have 'personelIDNumber', I want to get 'personal_ID_Number'. right now it gives personal_IDN_umber – Sid Jul 26 '11 at 15:01
  • 3
    How should I distinguish if the last uppercase belongs to last word or if it is the first of the next one? I think there is no way, because the pattern has no idea of the meaning of the word. Or you say every word starts with an uppercase. – stema Jul 26 '11 at 15:38
0

Non-regex solution (just in case)

    string str = "personalIDnumber";
    var result =
        Enumerable.Range(0, str.Length - 1)
            .Where(i => char.IsUpper(str[i]) != char.IsUpper(str[i + 1]))
            .ToList();

    string resultString = result.Aggregate(str, (current, i) => current.Insert(i + 1 + result.IndexOf(i), "_"));

the result stores a list of locations where an _ has to be inserted and the Aggregate() function inserts it.

Bala R
  • 107,317
  • 23
  • 199
  • 210
  • I got it working, I used "(?x)( [A-Z][a-z,0-9]+ | [A-Z]+(?![a-z]))" with _$1, and I got output with _ in from if the string started with a Capital letter, I stripped off the first underscore form string. Thanks Everyone. – Sid Jul 26 '11 at 18:14