Let say I've a few string: CustomerName, CustomerID, ContactNumber,...How can I transform those string to Customer Name, Customer ID, Contact Number? Is there any built-in method can be used to achieve that in c#? Or should I do it one by one manually?
Asked
Active
Viewed 430 times
0
-
1Regex? Regex.Replace(<>, @"([a-z])([A-Z])", "$1 $2") – Sebastian Schumann Jul 07 '15 at 09:01
-
I'd possibly use attributes, like the `DescriptionAttribute` (to make use of a built-in one) or better yet, implement a `FriendlyName(string name)` attribute to apply. This means not having to implement what you're suggesting altogether. – Grant Thomas Jul 07 '15 at 09:03
3 Answers
2
There's no built-in method for what you are trying to achieve other than a regex based one (see solution 2).
Solution 1 (no regex, custom method):
static string SeparateTitleCases(this string source, string separator = " ")
{
var result = new StringBuilder();
char previousChar = default(char);
for (int i = 0; i < source.Length; i++)
{
char currentChar = source[i];
if (char.IsLower(previousChar) && // Previous char is lowercase
char.IsUpper(currentChar)) // Current char is uppercase
{
result.Append(separator); // Append separator
}
result.Append(currentChar);
previousChar = currentChar;
}
return result.ToString();
}
Sample usage:
Console.WriteLine("CustomerName".SeparateTitleCases()); // Customer Name
Console.WriteLine("CustomerID".SeparateTitleCases()); // Customer ID
Console.WriteLine("CustomerName CustomerID".SeparateTitleCases()); // Customer Name Customer ID
Solution 2 (regex):
string pattern = @"([^\s])([A-Z]+[a-z]*)";
string replacement = "$1 $2";
Console.WriteLine(Regex.Replace("CustomerName", pattern, replacement)); // Customer Name
Console.WriteLine(Regex.Replace("CustomerID", pattern, replacement)); // Customer ID
Console.WriteLine(Regex.Replace("CustomerName CustomerID", pattern, replacement)); // Customer Name Customer ID

Jaanus Varus
- 3,508
- 3
- 31
- 49
-
Yes, there's something like this implemented in various libraries. I think there's no reason to implement this again. – rdoubleui Jul 07 '15 at 09:04
1
You could use this extension method:
private static readonly HashSet<UnicodeCategory> SeparatorCharCategories = new HashSet<UnicodeCategory>{ UnicodeCategory.UppercaseLetter, UnicodeCategory.TitlecaseLetter, UnicodeCategory.DecimalDigitNumber };
public static String SeparateCharCategories(this string input, string delimiter = " ")
{
StringBuilder sb = new StringBuilder(input.Length);
UnicodeCategory lastCharCategory = Char.GetUnicodeCategory(input[0]);
for(int i = 0; i < input.Length; i++)
{
UnicodeCategory charCategory = Char.GetUnicodeCategory(input[i]);
if (lastCharCategory != charCategory && SeparatorCharCategories.Contains(charCategory))
sb.Append(delimiter);
sb.Append(input[i]);
lastCharCategory = charCategory;
}
return sb.ToString();
}
Your samples and other edge cases:
var items = new[] { "CustomerName", "CustomerID", "ContactNumber", "PurchaseOrders", "purchaseOrders", "The2Unlimited", "Unlimited2", "222Unlimited", "The222Unlimited", "Unlimited222", "ATeam", "TheATeam", "TeamA", "HTMLGuide", "TheHTMLGuide", "TheGuideToHTML", "HTMLGuide5", "TheHTML5Guide", "TheGuideToHTML5", "TheUKAllStars", "AllStarsUK", "UKAllStars" };
foreach (string str in items)
Console.WriteLine(str.SeparateCharCategories(" "));
You see that acronyms are not supported, so HTMLGuide
remains HTMLGuide
:
Customer Name
Customer ID
Contact Number
Purchase Orders
purchase Orders
The 2 Unlimited
Unlimited 2
222 Unlimited
The 222 Unlimited
Unlimited 222
ATeam
The ATeam
Team A
HTMLGuide
The HTMLGuide
The Guide To HTML
HTMLGuide 5
The HTML 5 Guide
The Guide To HTML 5
The UKAll Stars
All Stars UK
UKAll Stars

Tim Schmelter
- 450,073
- 74
- 686
- 939
-
What to expect from `"BuildABear"` or `"RentAHouse"`? _Addition:_ `"CustomerIDNumber"` – Jeppe Stig Nielsen Jul 07 '15 at 09:20
-
-
This method returns `Customer IDNumber`, not sure what OP expects. – Tim Schmelter Jul 07 '15 at 09:35
-
1@JeppeStigNielsen: what do you expect from `"CUSTOMER"`? Surely not `"C U S T O M E R"` – Tim Schmelter Jul 07 '15 at 10:09
-
You get my (unclear) point. It is not really well-defined what we want. I would expect `"CustomerIDNumber"` to become `"Customer ID Number"`, and [`"ASCIIEncoding"`](https://msdn.microsoft.com/en-us/library/system.text.asciiencoding.aspx) to become `"ASCII Encoding"`. But consecutive one-letter words as in `"IAMan"` ("I, a man") we cannot handle, so that would become `"IA Man"`, not `"I A Man"`. (English does not have that many one-letter words.) By the way, the naming `ASCIIEncoding` is bad. For acronyms with three or more letters, one should use the form `AsciiEncoding` instead. – Jeppe Stig Nielsen Jul 07 '15 at 10:36
-
Also, one could consider numerals, as in [`"UTF8Encoding"`](https://msdn.microsoft.com/en-us/library/system.text.utf8encoding.aspx) or [`"SHA384Cng"`](https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha384cng.aspx). – Jeppe Stig Nielsen Jul 07 '15 at 10:50
-
[This answer from a linked thread](http://stackoverflow.com/a/26876094/1336654) contains a list of test cases. If we cannot define the behavior we want, we can at least require that the test cases from that list pass. – Jeppe Stig Nielsen Jul 07 '15 at 11:04
-
This approach doesn't support acronyms. Period ;-) OP hasn't asked for a solution that supports acronyms (which language btw?). If he also wants to separate other characters like digits he could modify the `if(wasLower && (charType == ...`-part, f.e. to include `UnicodeCategory.DecimalDigitNumber`. – Tim Schmelter Jul 07 '15 at 11:13
-
@JeppeStigNielsen: i have edited my answer anyway. This approach is easier and more flexible. – Tim Schmelter Jul 07 '15 at 11:41
0
I'm assuming that CustomerName
, CustomerID
are property names? You would need some way to reflect those names and you could then use the Humanizer Lib to add the whitespaces.
Use it like this:
"CustomerName".Humanize(LetterCasing.Title) => "Customer Name";

rdoubleui
- 3,554
- 4
- 30
- 51