Lets say we have string:
Hello
The user enters a char input "e"
What is the correct way of returning the string as the following using a regex method:
-e---
Code tried:
public static string updatedWord(char guess, string word)
{
string result = Regex.Replace(word, guess, "-");
console.writeline(result);
return result;
}
Assuming the input were e, you could build the following regex pattern:
[^e]
Then, do a global replacement on this pattern, which matches any single character which is not e, and replace it with a single dash.
string word = "Hello";
char guess = 'e';
string regex = "[^" + guess + "]";
string result = Regex.Replace(word, regex, "-");
Console.WriteLine(result);
This prints:
-e---
Note that to ensure that we handle regex metacharacters correctly, should they be allowed as inputs, we can wrap the regex pattern above in Regex.Escape:
Regex.Escape(regex)
This can be done without Regex, you need to "loop" all characters of the secret word and replace not yet guessed characters with -, regex will loop letters also, but c# methods are more comprehensible ;)
You need to keep collection of already guessed letters.
public class Guess
{
private readonly string _word;
private readonly HashSet<char> _guessed;
public Guess(string word)
{
_word = word;
_guessed = new HashSet<char>();
}
public string Try(char letter)
{
_guessed.Add(letter);
var maskedLetters = _word.Select(c => _guessed.Contains(c) ? c : '-').ToArray();
return new string(maskedLetters);
}
}
Usage
var game = new Guess("Hello");
var result = game.Try('e');
Console.WriteLine(result); // "-e---"
Related
I have a problem to find the pattern that solves the problem in onestep.
The string looks like this:
Text1
Text1$Text2$Text3
Text1$Text2$Text3$Text4$Text5$Text6 etc.
What i want to get is: Take up to 4x Text. If there are more than "4xText" take only the last sign.
Example:
Text1$Text2$Text3$Text4$Text5$Text6 -> Text1$Text2$Text3$Text4&56
My current solution is:
First pattern:
^([^\$]*)\$?([^\$]*)\$?([^\$]*)\$?([^\$]*)\$?
After this i will do a substitution with the first pattern
New string: Text5$Text6
second pattern is:
([^\$])\b
result: 56
combine both and get the result:
Text1$Text2$Text3$Text4$56
For me it is not clear why i cant easily put the second pattern after the first pattern into one pattern. Is there something like an anchor that tells the engine to start the pattern from here like it would do if is would be the only pattern ?
You might use an alternation with a positive lookbehind and then concatenate the matches.
(?<=^(?:[^$]+\$){0,3})[^$]+\$?|[^$](?=\$|$)
Explanation
(?<= Positive lookbehind, assert what is on the left is
^(?:[^$]+\$){0,3} Match 0-3 times any char except $ followed by an optional $
) Close lookbehind
[^$]+\$? Match 1+ times any char except $, then match an optional $
| Or
[^$] Match any char except $
(?=\$|$) Positive lookahead, assert what is directly to the right is either $ or the end of the string
.NET regex demo | C# demo
Example
string pattern = #"(?<=^(?:[^$]*\$){0,3})[^$]*\$?|[^$](?=\$|$)";
string[] strings = {
"Text1",
"Text1$Text2$Text3",
"Text1$Text2$Text3$Text4$Text5$Text6"
};
Regex regex = new Regex(pattern);
foreach (String s in strings) {
Console.WriteLine(string.Join("", from Match match in regex.Matches(s) select match.Value));
}
Output
Text1
Text1$Text2$Text3
Text1$Text2$Text3$Text4$56
I strongly believe regular expression isn't the way to do that. Mostly because of the readability.
You may consider using simple algorithm like this one to reach your goal:
using System;
public class Program
{
public static void Main()
{
var input = "Text1$Text2$Text3$Text4$Text5$Text6";
var parts = input.Split('$');
var result = "";
for(var i=0; i<parts.Length; i++){
result += (i <= 4 ? parts[i] + "$" : parts[i].Substring(4));
}
Console.WriteLine(result);
}
}
There are also linq alternatives :
using System;
using System.Linq;
public class Program
{
public static void Main()
{
var input = "Text1$Text2$Text3$Text4$Text5$Text6";
var parts = input.Split('$');
var first4 = parts.Take(4);
var remainings = parts.Skip(4);
var result2 = string.Join("$", first4) + "$" + string.Join("", remainings.Select( r=>r.Substring(4)));
Console.WriteLine(result2);
}
}
It has to be adjusted to the actual needs but the idea is there
Try this code:
var texts = new string[] {"Text1", "Text1$Text2$Text3", "Text1$Text2$Text3$Text4$Text5$Text6" };
var parsed = texts
.Select(s => Regex.Replace(s,
#"(Text\d{1,3}(?:\$Text\d{1,3}){0,3})((?:\$Text\d{1,3})*)",
(match) => match.Groups[1].Value +"$"+ match.Groups[2].Value.Replace("Text", "").Replace("$", "")
)).ToArray();
// parsed is now: string[3] { "Text1$", "Text1$Text2$Text3$", "Text1$Text2$Text3$Text4$56" }
Explanation:
solution uses regex pattern: (Text\d{1,3}(?:\$Text\d{1,3}){0,3})((?:\$Text\d{1,3})*)
(...) - first capturing group
(?:...) - non-capturing group
Text\d{1,3}(?:\$Text\d{1,3} - match Text literally, then match \d{1,3}, which is 1 up to three digits, \$ matches $ literally
Rest is just repetition of it. Basically, first group captures first four pieces, second group captures the rest, if any.
We also use MatchEvaluator here which is delegate type defined as:
public delegate string MatchEvaluator(Match match);
We define such method:
(match) => match.Groups[1].Value +"$"+ match.Groups[2].Value.Replace("Text", "").Replace("$", "")
We use it to evaluate match, so takee first capturing group and concatenate with second, removing unnecessary text.
It's not clear to me whether your goal can be achieved using exclusively regex. If nothing else, the fact that you want to introduce a new character '&' into the output adds to the challenge, since just plain matching would never be able to accomplish that. Possibly using the Replace() method? I'm not sure that would work though...using only a replacement pattern and not a MatchEvaluator, I don't see a way to recognize but still exclude the "$Text" portion from the fifth instance and later.
But, if you are willing to mix regex with a small amount of post-processing, you can definitely do it:
static readonly Regex regex1 = new Regex(#"(Text\d(?:\$Text\d){0,3})(?:\$Text(\d))*", RegexOptions.Compiled);
static void Main(string[] args)
{
for (int i = 1; i <= 6; i++)
{
string text = string.Join("$", Enumerable.Range(1, i).Select(j => $"Text{j}"));
WriteLine(KeepFour(text));
}
}
private static string KeepFour(string text)
{
Match match = regex1.Match(text);
if (!match.Success)
{
return "[NO MATCH]";
}
StringBuilder result = new StringBuilder();
result.Append(match.Groups[1].Value);
if (match.Groups[2].Captures.Count > 0)
{
result.Append("&");
// Have to iterate (join), because we don't want the whole match,
// just the captured text.
result.Append(JoinCaptures(match.Groups[2]));
}
return result.ToString();
}
private static string JoinCaptures(Group group)
{
return string.Join("", group.Captures.Cast<Capture>().Select(c => c.Value));
}
The above breaks your requirement into three different capture groups in a regex. Then it extracts the captured text, composing the result based on the results.
I want to split camelCase or PascalCase words to space separate collection of words.
So far, I have:
Regex.Replace(value, #"(\B[A-Z]+?(?=[A-Z][^A-Z])|\B[A-Z]+?(?=[^A-Z]))", " $0", RegexOptions.Compiled);
It works fine for converting "TestWord" to "Test Word" and for leaving single words untouched, e.g. Testing remains Testing.
However, ABCTest gets converted to A B C Test when I would prefer ABC Test.
Try:
[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z])|[a-z]+|[A-Z]+
An example on Regex101
How is it used in CS?
string strText = " TestWord asdfDasdf ABCDef";
string[] matches = Regex.Matches(strText, #"[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z])|[a-z]+|[A-Z]+")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
string result = String.Join(" ", matches);
result = 'Test Word asdf Dasdf ABC Def'
How it works
In the example string:
TestWord qwerDasdf
ABCTest Testing ((*&^%$CamelCase!"£$%^^))
asdfAasdf
AaBbbCD
[A-Z][a-z]+ matches:
[0-4] Test
[4-8] Word
[13-18] Dasdf
[22-26] Test
[27-34] Testing
[45-50] Camel
[50-54] Case
[68-73] Aasdf
[74-76] Aa
[76-79] Bbb
[A-Z]+(?=[A-Z][a-z]) matches:
[19-22] ABC
[a-z]+ matches:
[9-13] qwer
[64-68] asdf
[A-Z]+ matches:
[79-81] CD
Here is my attempt:
(?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b)|(?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b)
This regex can be used with Regex.Replace and $0 as a replacement string.
Regex.Replace(value, #"(?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b)|(?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b)", " $0", RegexOptions.Compiled);
See demo
Regex Explanation:
Contains 2 alternatives to account for a chain of capital letters before or after lowercase letters.
(?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b) - first alternative that matches several uppercase letters that are not preceded with a start of string, word boundary or another uppercase letter, and that are followed by a lowercase letter or a word boundary,
(?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b) - the second alternative that matches a single capital letter that is not preceded with a start of string with optional uppercase letters right after, or word boundary and is followed by a lowercase letter or a word boundary that is not preceded by optional uppercase letters.
Do you have a requirement to use Regex? To be honest, I wouldn't use Regex for this at all. They're hard to debug and not especially readable.
You also sometimes end up with all sorts of fun like this: Regex problem: IsMatch method never returns
The regex above will not deal with the wonderful world of unicode - e.g. Cyrillics (http://en.wikipedia.org/wiki/Cyrillic_script) (not that your specific problem domain probably needs this, but for completeness...)
I would go with a small, reusable, easily testable extension method:
class Program
{
static void Main(string[] args)
{
string[] inputs = new[]
{
"ABCTest",
"HelloWorld",
"testTest$Test",
"aaҚbb"
};
var output = inputs.Select(x => x.SplitWithSpaces(CultureInfo.CurrentUICulture));
foreach (string x in output)
{
Console.WriteLine(x);
}
Console.Read();
}
}
public static class StringExtensions
{
public static bool IsLowerCase(this TextInfo textInfo, char input)
{
return textInfo.ToLower(input) == input;
}
public static string SplitWithSpaces(this string input, CultureInfo culture = null)
{
if (culture == null)
{
culture = CultureInfo.InvariantCulture;
}
TextInfo textInfo = culture.TextInfo;
StringBuilder sb = new StringBuilder(input);
for (int i = 1; i < sb.Length; i++)
{
int previous = i - 1;
if (textInfo.IsLowerCase(sb[previous]))
{
int insertLocation = previous - 1;
if (insertLocation > 0)
{
sb.Insert(insertLocation, ' ');
}
while (i < sb.Length && textInfo.IsLowerCase(sb[i]))
{
i++;
}
}
}
return sb.ToString();
}
}
Consider two regular expressions:
var regex_A = "Main\.(.+)\.Value";
var regex_B = "M_(.+)_Sp";
I want to be able to replace a string using regex_A as input, and regex_B as the replacement string. But also the other way around. And without supplying additional information like a format string per regex.
Specifically I want to create a replaced_B string from an input_A string. So:
var input_A = "Main.Rotating.Value";
var replaced_B = input_A.RegEx_Awesome_Replace(regex_A, regex_B);
Assert.AreEqual("M_Rotating_Sp", replaced_B);
And this should also work in reverse (thats the reason i can't use a simple string.format for regex_B). Because I don't want to supply a format string for every regular expression (i'm lazy).
var input_B = "M_Skew_Sp";
var replaced_A = input_B.RegEx_Awesome_Replace(regex_B, regex_A);
Assert.AreEqual("Main.Skew.Value", replaced_A);
I have no clue if this exists, or how to call it. Google search finds me all kinds of other regex replaces... not this one.
Update:
So basically I need a way to convert a regular expression to a format string.
var regex_A_format = Regex2Format(regex_A);
Assert.AreEqual("Main.$1.Value", regex_A_format);
and
var regex_B_format = Regex2Format(regex_B);
Assert.AreEqual("M_$1_Sp", regex_B_format);
So what should the RegEx_Awesome_Replace and/or Regex2Format function look like?
Update 2:
I guess the RegEx_Awesome_Replace should look something like (using some code from answers below):
public static class StringExtenstions
{
public static string RegExAwesomeReplace(this string inputString,string searchPattern,string replacePattern)
{
return Regex.Replace(inputString, searchPattern, Regex2Format(replacePattern));
}
}
Which would leave the Regex2Format as an open question.
There is no defined way for one regex to refer to a match found in another regex. Regexes are not format strings.
What you can do is to use Tuples of a format string together with its regex. e.g.
var a = new Tuple<Regex,string>(new Regex(#"(?<=Main\.).+(?=\.Value)"), #"Main.{0}.Value")
var b = new Tuple<Regex,string>(new Regex(#"(?<=M_).+(?=_Sp)"), #"M_{0}_Sp")`
Then you can pass these objects to a common replacement method in any order, like this:
private string RegEx_Awesome_Replace(string input, Tuple<Regex,string> toFind, Tuple<Regex,string> replaceWith)
{
return string.Format(replaceWith.Item2, toFind.Item1.Match(input).Value);
}
You will notice that I have used zero-width positive lookahead assertion and zero-width positive lookbehind assertions in my regexes, to ensure that Value contains exactly the text that I want to replace.
You may also want to add error handling, for cases where the match can not be found. Maybe read about Regex.Match
Since you have already reduced your problem to where you need to change a Regex into a string format (implementing Regex2Format) I will focus my answer just on that part. Note that my answer is incomplete because it doesn't address the full breadth of parsing regex capturing groups, however it works for simple cases.
First thing needed is a Regex that will match Regex capture groups. There is a negative lookbehind to not match escaped bracket symbols. There are other cases that break this regex. E.g. a non-capturing group, wildcard symbols, things between square braces.
private static readonly Regex CaptureGroupMatcher = new Regex(#"(?<!\\)\([^\)]+\)");
The implementation of Regex2Format here basically writes everything outside of capture groups into the output string, and replaces the capture group value by {x}.
static string Regex2Format(string pattern)
{
var targetBuilder = new StringBuilder();
int previousEndIndex = 0;
int formatIndex = 0;
foreach (Match match in CaptureGroupMatcher.Matches(pattern))
{
var group = match.Groups[0];
int endIndex = group.Index;
AppendPart(pattern, previousEndIndex, endIndex, targetBuilder);
targetBuilder.Append('{');
targetBuilder.Append(formatIndex++);
targetBuilder.Append('}');
previousEndIndex = group.Index + group.Length;
}
AppendPart(pattern, previousEndIndex, pattern.Length, targetBuilder);
return targetBuilder.ToString();
}
This helper function writes pattern string values into the output, it currently writes everything except \ characters used to escape something.
static void AppendPart(string pattern, int previousEndIndex, int endIndex, StringBuilder targetBuilder)
{
for (int i = previousEndIndex; i < endIndex; i++)
{
char c = pattern[i];
if (c == '\\' && i < pattern.Length - 1 && pattern[i + 1] != '\\')
{
//backslash not followed by another backslash - it's an escape char
}
else
{
targetBuilder.Append(c);
}
}
}
Test cases
static void Test()
{
var cases = new Dictionary<string, string>
{
{ #"Main\.(.+)\.Value", #"Main.{0}.Value" },
{ #"M_(.+)_Sp(.*)", "M_{0}_Sp{1}" },
{ #"M_\(.+)_Sp", #"M_(.+)_Sp" },
};
foreach (var kvp in cases)
{
if (PatternToStringFormat(kvp.Key) != kvp.Value)
{
Console.WriteLine("Test failed for {0} - expected {1} but got {2}", kvp.Key, kvp.Value, PatternToStringFormat(kvp.Key));
}
}
}
To wrap up, here is the usage:
private static string AwesomeRegexReplace(string input, string sourcePattern, string targetPattern)
{
var targetFormat = PatternToStringFormat(targetPattern);
return Regex.Replace(input, sourcePattern, match =>
{
var args = match.Groups.OfType<Group>().Skip(1).Select(g => g.Value).ToArray<object>();
return string.Format(targetFormat, args);
});
}
Something like this might work
var replaced_B = Regex.Replace(input_A, #"Main\.(.+)\.Value", #"M_$1_Sp");
Are you looking for something like this?
public static class StringExtenstions
{
public static string RegExAwesomeReplace(this string inputString,string searchPattern,string replacePattern)
{
Match searchMatch = Regex.Match(inputString,searchPattern);
Match replaceMatch = Regex.Match(inputString, replacePattern);
if (!searchMatch.Success || !replaceMatch.Success)
{
return inputString;
}
return inputString.Replace(searchMatch.Value, replaceMatch.Value);
}
}
The string extension method returns the string with replaced value for search pattern and replace pattern.
This is how you call:
input_A.RegEx_Awesome_Replace(regex_A, regex_B);
Can I do something like following to remove specific strings from the end of the words ?
public static HashSet<string> stringtoremove = new HashSet<string>
...............
.................
public static string stepone(this string word)
{
if (stringtoremove(word.EndsWith))
{
word = ..................................;
}
return word;
}
I tried but it doesn't work. did i miss something in my code ? thanks in advance.
The best option is to use Regular Expressions; have a look at the Replace method.
string input = "test testabc test123 abc abctest";
string pattern = #"(abc\b)";
string replacement = "";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(input, replacement);
Console.WriteLine("Original String: {0}", input);
Console.WriteLine("Replacement String: {0}", result);
I assume that you actually want to look into the HashSet<String> to see if the given string parameter ends with one of these words. If so, remove it from the end of the string.
You can use FirstOrDefault to determine the first string in the set that is also the end of the given word:
var firstMatch = stringtoremove.FirstOrDefault(str => word.EndsWith(str));
if (firstMatch != null)
return word.Substring(0, word.Length - firstMatch.Length);
else
return word;
Why don't you use String.TrimEnd method?
word = word.TrimEnd(charsToTrim)
Is there an easy way to capitalize the first letter of a string and lower the rest of it? Is there a built in method or do I need to make my own?
TextInfo.ToTitleCase() capitalizes the first character in each token of a string.
If there is no need to maintain Acronym Uppercasing, then you should include ToLower().
string s = "JOHN DOE";
s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());
// Produces "John Doe"
If CurrentCulture is unavailable, use:
string s = "JOHN DOE";
s = new System.Globalization.CultureInfo("en-US", false).TextInfo.ToTitleCase(s.ToLower());
See the MSDN Link for a detailed description.
CultureInfo.CurrentCulture.TextInfo.ToTitleCase("hello world");
String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test);
The above code wont work .....
so put the below code by convert to lower then apply the function
String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test.ToLower());
There are some cases that CultureInfo.CurrentCulture.TextInfo.ToTitleCase cannot handle, for example : the apostrophe '.
string input = CultureInfo.CurrentCulture.TextInfo.ToTitleCase("o'reilly, m'grego, d'angelo");
// input = O'reilly, M'grego, D'angelo
A regex can also be used \b[a-zA-Z] to identify the starting character of a word after a word boundary \b, then we need just to replace the match by its upper case equivalence thanks to the Regex.Replace(string input,string pattern,MatchEvaluator evaluator) method :
string input = "o'reilly, m'grego, d'angelo";
input = Regex.Replace(input.ToLower(), #"\b[a-zA-Z]", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo
The regex can be tuned if needed, for instance, if we want to handle the MacDonald and McFry cases the regex becomes : (?<=\b(?:mc|mac)?)[a-zA-Z]
string input = "o'reilly, m'grego, d'angelo, macdonald's, mcfry";
input = Regex.Replace(input.ToLower(), #"(?<=\b(?:mc|mac)?)[a-zA-Z]", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo, MacDonald'S, McFry
If we need to handle more prefixes we only need to modify the group (?:mc|mac), for example to add french prefixes du, de : (?:mc|mac|du|de).
Finally, we can realize that this regex will also match the case MacDonald'S for the last 's so we need to handle it in the regex with a negative look behind (?<!'s\b). At the end we have :
string input = "o'reilly, m'grego, d'angelo, macdonald's, mcfry";
input = Regex.Replace(input.ToLower(), #"(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b)", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo, MacDonald's, McFry
Mc and Mac are common surname prefixes throughout the US, and there are others. TextInfo.ToTitleCase doesn't handle those cases and shouldn't be used for this purpose. Here's how I'm doing it:
public static string ToTitleCase(string str)
{
string result = str;
if (!string.IsNullOrEmpty(str))
{
var words = str.Split(' ');
for (int index = 0; index < words.Length; index++)
{
var s = words[index];
if (s.Length > 0)
{
words[index] = s[0].ToString().ToUpper() + s.Substring(1);
}
}
result = string.Join(" ", words);
}
return result;
}
ToTitleCase() should work for you.
http://support.microsoft.com/kb/312890
The most direct option is going to be to use the ToTitleCase function that is available in .NET which should take care of the name most of the time. As edg pointed out there are some names that it will not work for, but these are fairly rare so unless you are targeting a culture where such names are common it is not necessary something that you have to worry too much about.
However if you are not working with a .NET langauge, then it depends on what the input looks like - if you have two separate fields for the first name and the last name then you can just capitalize the first letter lower the rest of it using substrings.
firstName = firstName.Substring(0, 1).ToUpper() + firstName.Substring(1).ToLower();
lastName = lastName.Substring(0, 1).ToUpper() + lastName.Substring(1).ToLower();
However, if you are provided multiple names as part of the same string then you need to know how you are getting the information and split it accordingly. So if you are getting a name like "John Doe" you an split the string based upon the space character. If it is in a format such as "Doe, John" you are going to need to split it based upon the comma. However, once you have it split apart you just apply the code shown previously.
CultureInfo.CurrentCulture.TextInfo.ToTitleCase ("my name");
returns ~ My Name
But the problem still exists with names like McFly as stated earlier.
I use my own method to get this fixed:
For example the phrase: "hello world. hello this is the stackoverflow world." will be "Hello World. Hello This Is The Stackoverflow World.". Regex \b (start of a word) \w (first charactor of the word) will do the trick.
/// <summary>
/// Makes each first letter of a word uppercase. The rest will be lowercase
/// </summary>
/// <param name="Phrase"></param>
/// <returns></returns>
public static string FormatWordsWithFirstCapital(string Phrase)
{
MatchCollection Matches = Regex.Matches(Phrase, "\\b\\w");
Phrase = Phrase.ToLower();
foreach (Match Match in Matches)
Phrase = Phrase.Remove(Match.Index, 1).Insert(Match.Index, Match.Value.ToUpper());
return Phrase;
}
The suggestions to use ToTitleCase won't work for strings that are all upper case. So you are gonna have to call ToUpper on the first char and ToLower on the remaining characters.
This class does the trick. You can add new prefixes to the _prefixes static string array.
public static class StringExtensions
{
public static string ToProperCase( this string original )
{
if( String.IsNullOrEmpty( original ) )
return original;
string result = _properNameRx.Replace( original.ToLower( CultureInfo.CurrentCulture ), HandleWord );
return result;
}
public static string WordToProperCase( this string word )
{
if( String.IsNullOrEmpty( word ) )
return word;
if( word.Length > 1 )
return Char.ToUpper( word[0], CultureInfo.CurrentCulture ) + word.Substring( 1 );
return word.ToUpper( CultureInfo.CurrentCulture );
}
private static readonly Regex _properNameRx = new Regex( #"\b(\w+)\b" );
private static readonly string[] _prefixes = {
"mc"
};
private static string HandleWord( Match m )
{
string word = m.Groups[1].Value;
foreach( string prefix in _prefixes )
{
if( word.StartsWith( prefix, StringComparison.CurrentCultureIgnoreCase ) )
return prefix.WordToProperCase() + word.Substring( prefix.Length ).WordToProperCase();
}
return word.WordToProperCase();
}
}
If your using vS2k8, you can use an extension method to add it to the String class:
public static string FirstLetterToUpper(this String input)
{
return input = input.Substring(0, 1).ToUpper() +
input.Substring(1, input.Length - 1);
}
To get round some of the issues/problems that have ben highlighted I would suggest converting the string to lower case first and then call the ToTitleCase method. You could then use IndexOf(" Mc") or IndexOf(" O\'") to determine special cases that need more specific attention.
inputString = inputString.ToLower();
inputString = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(inputString);
int indexOfMc = inputString.IndexOf(" Mc");
if(indexOfMc > 0)
{
inputString.Substring(0, indexOfMc + 3) + inputString[indexOfMc + 3].ToString().ToUpper() + inputString.Substring(indexOfMc + 4);
}
I like this way:
using System.Globalization;
...
TextInfo myTi = new CultureInfo("en-Us",false).TextInfo;
string raw = "THIS IS ALL CAPS";
string firstCapOnly = myTi.ToTitleCase(raw.ToLower());
Lifted from this MSDN article.
Hope this helps you.
String fName = "firstname";
String lName = "lastname";
String capitalizedFName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fName);
String capitalizedLName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(lName);
public static string ConvertToCaptilize(string input)
{
if (!string.IsNullOrEmpty(input))
{
string[] arrUserInput = input.Split(' ');
// Initialize a string builder object for the output
StringBuilder sbOutPut = new StringBuilder();
// Loop thru each character in the string array
foreach (string str in arrUserInput)
{
if (!string.IsNullOrEmpty(str))
{
var charArray = str.ToCharArray();
int k = 0;
foreach (var cr in charArray)
{
char c;
c = k == 0 ? char.ToUpper(cr) : char.ToLower(cr);
sbOutPut.Append(c);
k++;
}
}
sbOutPut.Append(" ");
}
return sbOutPut.ToString();
}
return string.Empty;
}
Like edg indicated, you'll need a more complex algorithm to handle special names (this is probably why many places force everything to upper case).
Something like this untested c# should handle the simple case you requested:
public string SentenceCase(string input)
{
return input(0, 1).ToUpper + input.Substring(1).ToLower;
}