I've tried three approaches to get a ProperName solution for a string of all CAPS.
Here is my code:
string testStr = "SYNDEGAARD";
string result1 = UppercaseFirst(testStr);
string titleCase = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(testStr);
string result2 = titleCase;
CultureInfo culture_info = Thread.CurrentThread.CurrentCulture;
TextInfo text_info = culture_info.TextInfo;
string result3 = text_info.ToTitleCase(testStr);
private static string UppercaseFirst(string s)
{
// Check for empty string.
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
// Return char and concat substring.
return char.ToUpper(s[0]) + s.Substring(1);
}
All three results are "SYNDENGAARD". It never changes to "Syndengaard".
The reason why you can't get the result you wanted is because ToTitleCase() doesn't work if the input string is all in capital letters.
You can try changing SYNDEGAARD to SYNDEGAARDx and see the difference.
As to why that's the default behavior I am not sure.
Also you forgot to add ToLower() in this function to make sure that the preceding texts will be in lowercase.
private static string UppercaseFirst(string s)
{
// Check for empty string.
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
// Return char and concat substring.
return char.ToUpper(s[0]) + s.Substring(1).ToLower(); // Missing ToLower()
}
EDIT:
Here's why nothing happens for uppercase texts.
TextInfo.ToTitleCase Method (String).
Converts the specified string to title case (except for words that are
entirely in uppercase, which are considered to be acronyms).
Use Humanizer, it will provide you with the range of utilities for conversions and manipulate strings, enums, dates, times, timespans, numbers and quantities.
https://github.com/Humanizr/Humanizer
Nuget Package
https://www.nuget.org/packages/Humanizer/
Var name = "shyam bhagat";
var titleCase = name.Humanize(LetterCasing.Title);
Just update to this
return char.ToUpper(s[0]) + s.Substring(1).ToLower();
Related
I need to extract a variable length decimal number from a string using c# and .NET. The input string is like $PTNTHPR,352.5,N,2.3,N,4.6,N,16*. I need the first occurrence of decimal number, i.e the 352.5 part. The numerical value ranges from 0.0 to 360.0 and I need that number from that string.
I searched a lot and got solution for a fixed length sub string but here I have variable length to extract. I have not tried with any code yet.
If it is always in this format you can use String.Split and decimal.Parse
var data = #"$PTNTHPR,352.5,N,2.3,N,4.6,N,16*";
var d = decimal.Parse(data.Split(new[]{','})[1]);
Console.WriteLine(d);
This is just a sample code to guide you. You should add additional exception handling logic to this, Also consider using decimal.TryParse
If you want to find the first occurance of decimal value you split the string and parse them one by one.
var data = #"$PTNTHPR,352.5,N,2.3,N,4.6,N,16*";
var splited = data.Split(new[]{','});
decimal? value = null;
foreach (var part in splited)
{
decimal parsed;
if (decimal.TryParse(part, out parsed))
{
value = parsed;
break;
}
}
Console.WriteLine(value);
First occurence in any of the tokens? Use String.Split to separate them and LINQ to find the first. You can use decimal.TryParse to check if it's parsable:
decimal? firstParsableToken = "$PTNTHPR,352.5,N,2.3,N,4.6,N,16*".Split(',')
.Select(s => s.TryGetDecimal(NumberFormatInfo.InvariantInfo))
.FirstOrDefault(d => d.HasValue);
Used this simple extension method to parse it to decimal?:
public static decimal? TryGetDecimal(this string item, IFormatProvider formatProvider = null, NumberStyles nStyles = NumberStyles.Any)
{
if (formatProvider == null) formatProvider = NumberFormatInfo.CurrentInfo;
decimal d = 0m;
bool success = decimal.TryParse(item, nStyles, formatProvider, out d);
if (success)
return d;
else
return null;
}
If the string is always comma separated, can you not use string.Split() to get each section, then use double.TryParse() to test if that part is numeric?
public static class Helper
{
public static string MyExtract(this string s)
{
return s.Split(',').First(str => Regex.IsMatch(str, #"[0-9.,]"));
}
}
Use it like this: string str = "$PTNTHPR,352.5,N,2.3,N,4.6,N,16*".MyExtract();
Then convert it to double/decimal if you need it.
I've been using C# String.Format for formatting numbers before like this (in this example I simply want to insert a space):
String.Format("{0:### ###}", 123456);
output:
"123 456"
In this particular case, the number is a string. My first thought was to simply parse it to a number, but it makes no sense in the context, and there must be a prettier way.
Following does not work, as ## looks for numbers
String.Format("{0:### ###}", "123456");
output:
"123456"
What is the string equivalent to # when formatting? The awesomeness of String.Format is still fairly new to me.
You have to parse the string to a number first.
int number = int.Parse("123456");
String.Format("{0:### ###}", number);
of course you could also use string methods but that's not as reliable and less safe:
string strNumber = "123456";
String.Format("{0} {1}", strNumber.Remove(3), strNumber.Substring(3));
As Heinzi pointed out, you can not have format specifier for string arguments.
So, instead of String.Format, you may use following:
string myNum="123456";
myNum=myNum.Insert(3," ");
Not very beautiful, and the extra work might outweigh the gains, but if the input is a string on that format, you could do:
var str = "123456";
var result = String.Format("{0} {1}", str.Substring(0,3), str.Substring(3));
string is not a IFormattable
Console.WriteLine("123456" is IFormattable); // False
Console.WriteLine(21321 is IFormattable); // True
No point to supply a format if the argument is not IFormattable only way is to convert your string to int or long
We're doing string manipulation, so we could always use a regex.
Adapted slightly from here:
class MyClass
{
static void Main(string[] args)
{
string sInput, sRegex;
// The string to search.
sInput = "123456789";
// The regular expression.
sRegex = "[0-9][0-9][0-9]";
Regex r = new Regex(sRegex);
MyClass c = new MyClass();
// Assign the replace method to the MatchEvaluator delegate.
MatchEvaluator myEvaluator = new MatchEvaluator(c.ReplaceNums);
// Replace matched characters using the delegate method.
sInput = r.Replace(sInput, myEvaluator);
// Write out the modified string.
Console.WriteLine(sInput);
}
public string ReplaceNums(Match m)
// Replace each Regex match with match + " "
{
return m.ToString()+" ";
}
}
How's that?
It's been ages since I used C# and I can't test, but this may work as a one-liner which may be "neater" if you only need it once:
sInput = Regex("[0-9][0-9][0-9]").Replace(sInput,MatchEvaluator(Match m => m.ToString()+" "));
There is no way to do what you want unless you parse the string first.
Based on your comments, you only really need a simple formatting so you are better off just implementing a small helper method and thats it. (IMHO it's not really a good idea to parse the string if it isn't logically a number; you can't really be sure that in the future the input string might not be a number at all.
I'd go for something similar to:
public static string Group(this string s, int groupSize = 3, char groupSeparator = ' ')
{
var formattedIdentifierBuilder = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
if (i != 0 && (s.Length - i) % groupSize == 0)
{
formattedIdentifierBuilder.Append(groupSeparator);
}
formattedIdentifierBuilder.Append(s[i]);
}
return formattedIdentifierBuilder.ToString();
}
EDIT: Generalized to generic grouping size and group separator.
The problem is that # is a Digit placeholder and it is specific to numeric formatting only. Hence, you can't use this on strings.
Either parse the string to a numeric, so the formatting rules apply, or use other methods to split the string in two.
string.Format("{0:### ###}", int.Parse("123456"));
So what I am trying to do is as follows :
example of a string is A4PC
I am trying to replace for example any occurance of "A" with "[A4]" so I would get and similar any occurance of "4" with "[A4]"
"[A4][A4]PC"
I tried doing a normal Replace on the string but found out I got
"[A[A4]]PC"
string badWordAllVariants =
restriction.Value.Replace("A", "[A4]").Replace("4", "[A4]")
since I have two A's in a row causing an issue.
So I was thinking it would be better rather than the replace on the string I need to do it on a character per character basis and then build up a string again.
Is there anyway in Linq or so to do something like this ?
You don't need any LINQ here - String.Replace works just fine:
string input = "AAPC";
string result = input.Replace("A", "[A4]"); // "[A4][A4]PC"
UPDATE: For your updated requirements I suggest to use regular expression replace
string input = "A4PC";
var result = Regex.Replace(input, "A|4", "[A4]"); // "[A4][A4]PC"
This works well for me:
string x = "AAPC";
string replace = x.Replace("A", "[A4]");
EDIT:
Based on the updated question, the issue is the second replacement. In order to replace multiple strings you will want to do this sequentially:
var original = "AAPC";
// add arbitrary room to allow for more new characters
StringBuilder resultString = new StringBuilder(original.Length + 10);
foreach (char currentChar in original.ToCharArray())
{
if (currentChar == 'A') resultString.Append("[A4]");
else if (currentChar == '4') resultString.Append("[A4]");
else resultString.Append(currentChar);
}
string result = resultString.ToString();
You can run this routine with any replacements you want to make (in this case the letters 'A' and '4' and it should work. If you would want to replace strings the code would be similar in structure but you would need to "look ahead" and probably use a for loop. Hopefully this helps!
By the way - you want to use a string builder here and not strings because strings are static which means space gets allocated every time you loop. (Not good!)
I think this should do the trick
string str = "AA4PC";
string result = Regex.Replace(str, #"(?<Before>[^A4]?)(?<Value>A|4)(?<After>[^A4]?)", (m) =>
{
string before = m.Groups["Before"].Value;
string after = m.Groups["After"].Value;
string value = m.Groups["Value"].Value;
if (before != "[" || after != "]")
{
return "[A4]";
}
return m.ToString();
});
It is going to replace A and 4 that hasn't been replaced yet for [A4].
I am using C# 2.0 and I have got below type of strings:
string id = "tcm:481-191820"; or "tcm:481-191820-32"; or "tcm:481-191820-8"; or "tcm:481-191820-128";
The last part of string doesn't matter i.e. (-32,-8,-128), whatever the string is it will render below result.
Now, I need to write one function which will take above string as input. something like below and will output as "tcm:0-481-1"
public static string GetPublicationID(string id)
{
//this function will return as below output
return "tcm:0-481-1"
}
Please suggest!!
If final "-1" is static you could use:
public static string GetPublicationID(string id)
{
int a = 1 + id.IndexOf(':');
string first = id.Substring(0, a);
string second = id.Substring(a, id.IndexOf('-') - a);
return String.Format("{0}0-{1}-1", first, second);
}
or if "-1" is first part of next token, try this
public static string GetPublicationID(string id)
{
int a = 1 + id.IndexOf(':');
string first = id.Substring(0, a);
string second = id.Substring(a, id.IndexOf('-') - a + 2);
return String.Format("{0}0-{1}", first, second);
}
This syntax works even for different length patterns, assuming that your string is
first_part:second_part-anything_else
All you need is:
string.Format("{0}0-{1}", id.Substring(0,4), id.Substring(4,5));
This just uses substring to get the first four characters and then the next five and put them into the format with the 0- in there.
This does assume that your format is a fixed number of characters in each position (which it is in your example). If the string might be abcd:4812... then you will have to modify it slightly to pick up the right length of strings. See Marco's answer for that technique. I'd advise using his if you need the variable length and mine if the lengths stay the same.
Also as an additional note your original function of returning a static string does work for all of those examples you provided. I have assumed there are other numbers visible but if it is only the suffix that changes then you could happily use a static string (at which point declaring a constant or something rather than using a method would probably work better).
Obligatory Regular Expression Answer:
using System.Text.RegularExpressions;
public static string GetPublicationID(string id)
{
Match m = RegEx.Match(#"tcm:([\d]+-[\d]{1})", id);
if(m.Success)
return string.Format("tcm:0-{0}", m.Groups[1].Captures[0].Value.ToString());
else
return string.Empty;
}
Regex regxMatch = new Regex("(?<prefix>tcm:)(?<id>\\d+-\\d)(?<suffix>.)*",RegexOptions.Singleline|RegexOptions.Compiled);
string regxReplace = "${prefix}0-${id}";
string GetPublicationID(string input) {
return regxMatch.Replace(input, regxReplace);
}
string test = "tcm:481-191820-128";
stirng result = GetPublicationID(test);
//result: tcm:0-481-1
i have a string:
e.g. WORD1_WORD2_WORD3
how do i get just WORD1 from the string?
i.e the text before the first underscore
It may be tempting to say Split - but that involves the creating of an array and lots of individual strings. IMO, the optimal way here is to find the first underscore, and take a substring:
string b = s.Substring(0, s.IndexOf('_')); // assumes at least one _
(edit)
If you are doing this lots, you could add some extension methods:
public static string SubstringBefore(this string s, char value) {
if(string.IsNullOrEmpty(s)) return s;
int i = s.IndexOf(value);
return i > 0 ? s.Substring(0,i) : s;
}
public static string SubstringAfter(this string s, char value) {
if (string.IsNullOrEmpty(s)) return s;
int i = s.IndexOf(value);
return i >= 0 ? s.Substring(i + 1) : s;
}
then:
string s = "a_b_c";
string b = s.SubstringBefore('_'), c = s.SubstringAfter('_');
YOUR_STRING.Split('_')[0]
In fact the Split method returns an array of strings resulting from splitting the original string at any occurrence of the specified character(s), not including the character at which the split was performed.
if s is the string:
int idx = s.IndexOf('_');
if (idx >= 0)
firstPart = s.Substring(0,idx);
("WORD1_WORD2_WORD3").Split('_')[0]
should return "WORD1". If it doesn't work try .Spilt() on a string variable with the Content you specified.
string str="WORD1_WORD2_WORD3";
string result=str.Split('_')[0];
This actually returns an array:
{"WORD1", "WORD2", "WORD3"}
There are several ways. You can use Split, Substring. etc. An example with Split:
String var = "WORD1_WORD2_WORD3";
String result = var.Split('_')[0];