I wanted to do my program like a command prompt. I thought that it must perform some string methods.
For example: COM> length "string " must return the length of "string " (the command must be bigger than three characters, that is, len "asdf" is OK). In addition to this I added three methods, "reverse", "ToUpper" and "ToLower" and to escape, "quit", and it is not necessarily adjecent or not (can be any spaces between the command and the string).
I wrote on my way, but I think it is not optimized. So do you have any trick to make it faster and reusable?
(I didn't care about any exception so I know there are some exceptions.)
class Program
{
static void Main(string[] args)
{
string str;
for (; ; )
{
Console.Write("CSD>");
str = Console.ReadLine();
if (str == "quit")
break;
commandControl(str);
}
}
public static void commandControl(string str)
{
string strCom, strString;
int index;
str = str.Trim();
index = str.IndexOf(" ");
strCom = str.Substring(0, index);
str = str.Substring(index);
str = str.Trim();
strString = str.Substring(1, str.Length - 2);
string[] strComArry = { "length", "reverse", "upper", "lower" };
int i;
if (strCom.Length >= 3)
{
for (i = 0; i < strComArry.Length; i++)
if (strCom.Length <= strComArry[i].Length)
if (strCom == strComArry[i].Substring(0, strCom.Length))
break;
switch (i)
{
case 0:
Console.WriteLine(strString.Length);
break;
case 1:
for (int j = strString.Length - 1; j >= 0; --j)
System.Console.Write(strString[j]);
Console.WriteLine();
break;
case 2:
Console.WriteLine(strString.ToUpper());
break;
case 3:
Console.WriteLine(strString.ToLower());
break;
}
}
else
Console.WriteLine("Command must be more than 3 characters !...");
}
}
I'm not going to provide a full working example, but take a look at the snippet below. This idea is to use a dictionary of actions to store what to do with commands. That way, you can add new functionality to the interpreter by adding to the "Methods" dictionary.
The idea is call InitializeFunctions to register all of the functions you want available in the interpreter, and then call command control to interpret one.
(I gave two examples on how to add functions, a lambda syntax and referencing a normal function. Also those functions assume you have already parsed what is a command and what is a parameter, which you have done already in your example.)
static Dictionary<string, Action<string>> Methods = new Dictionary<string, Action<string>>();
public static void InitializeFunctions()
{
Methods.Add("ToLower", a => Console.WriteLine(a.ToLower()));
Methods.Add("ToUpper", ToUpper);
}
static void ToUpper(string str)
{
Console.WriteLine(str.ToUpper());
}
public static void commandControl(string str, string param)
{
if(str.Length < 4)
Console.WriteLine("Command must be more than 3 characters !...");
if (Methods.ContainsKey(str))
Methods[str].Invoke(param);
else
Console.WriteLine("Invalid Command");
}
Related
I am a student and got a task where I will have to make a program that solves first-grade equations. I will start of by making a textbox where I can write down different numbers of all the arithmetics, for example, 3+4*8 (it doesn't have to follow the priority rules) and then when I press the "go" button I get the answer.
I tried using the split method from this question/answer:
C# read and calculate multiple values from textbox and it worked for addition but then I tried to use the same script and change it up a little to make it work for multiplication and subtraction but it did not work.
The scripts that I have tried are:
string[] parts = tbxTal.Text.Split('+');
int intSumma = 0;
foreach (string item in parts)
{
intSumma = intSumma + Convert.ToInt32(item);
}
lblSvar.Text = intSumma.ToString();
Also tried using switch (+) after the split but it did not work since there is not + left after te splitt
Any Idea on how I can make a textbox that calculates everything inside of it? My teacher gave me a tip to use the split method and case method together.
Without giving the answer overtly, I would suggest that you keep a variable for the accumulator, operator, and operand. From there you can use a for loop to keep reading until you've evaluated all of the expression, then return the accumulator.
double Evaluate(string expression) {
double accumulator = 0;
double operand = 0;
string operator = string.Empty;
int index = 0;
while (index < expression.Length) {
operand = ExtractNextNumericValue(ref index, expression);
operator = ExtractNextOperator(ref index, expression);
// We now have everything we need to do the math
...
}
return accumulator;
}
public double ExtractNextNumericValue(ref index, string expression) {
// Use IndexOf on the string, use the index as a start location
// Make sure to update ref to be at the end of where you extracted your value
// You know that the value will come before an operator, so look for '+', '-', '*', '/'
...
}
One thing that should help you with creating a calculator like this is reversed Polish notation. Accepted answer to this question is a working calculator that can handle order of operations etc.
Code from mentioned post:
static void Main(string[] args)
{
String str = "5 + ( ( 1 + 2 ) * 4 ) −3";
String result=LengyelFormaKonvertalas(str);
Console.WriteLine(result.ToString());
Console.ReadLine();
}
static String LengyelFormaKonvertalas(String input) // this is the rpn method
{
Stack stack = new Stack();
String str = input.Replace(" ",string.Empty);
StringBuilder formula = new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
char x=str[i];
if (x == '(')
stack.Push(x);
else if (IsOperandus(x)) // is it operand
{
formula.Append(x);
}
else if (IsOperator(x)) // is it operation
{
if (stack.Count>0 && (char)stack.Peek()!='(' && Prior(x)<=Prior((char)stack.Peek()) )
{
char y = (char)stack.Pop();
formula.Append(y);
}
if (stack.Count > 0 && (char)stack.Peek() != '(' && Prior(x) < Prior((char)stack.Peek()))
{
char y = (char)stack.Pop();
formula.Append(y);
}
stack.Push(x);
}
else
{
char y=(char)stack.Pop();
if (y!='(')
{
formula.Append(y);
}
}
}
while (stack.Count>0)
{
char c = (char)stack.Pop();
formula.Append(c);
}
return formula.ToString();
}
static bool IsOperator(char c)
{
return (c=='-'|| c=='+' || c=='*' || c=='/');
}
static bool IsOperandus(char c)
{
return (c>='0' && c<='9' || c=='.');
}
static int Prior(char c)
{
switch (c)
{
case '=':
return 1;
case '+':
return 2;
case '-':
return 2;
case '*':
return 3;
case '/':
return 3;
case '^':
return 4;
default:
throw new ArgumentException("Rossz paraméter");
}
}
}
Change below line of code from this article C# read and calculate multiple values from textbox
like this:
string[] parts = textBox1.Text.Split('+');
Replace above line with below line
string[] parts = textBox1.Text.Split('+','*','-');
I am writing some code that replaces an old C exe. The original c file would read a file and then trim the contents and put them into two new files, a .c and a .h file. I am doing the same thing, but in C#. I have everything figured out, except for how to trim a function down so that only the function name and parameters are put into the .h file.
This is an example of two of the functions:
void
M_SCP_Msg_ClearNVMemory(
Marshal_dataFunc* _argDataFunc_, Marshal_dataFuncArg _argDataFuncArg_, void const* _argSrc_)
{
SCP_Msg_ClearNVMemory const* _src_ = (SCP_Msg_ClearNVMemory const*)_argSrc_;
M_uint8_t(_argDataFunc_, _argDataFuncArg_, &_src_->operation);
}
void
MA_SCP_Msg_ClearNVMemory(
Marshal_dataFunc* argDataFunc, Marshal_dataFuncArg argDataFuncArg,
void const* argSrc, unsigned argNSrcElem)
{
SCP_Msg_ClearNVMemory const* src = (SCP_Msg_ClearNVMemory const*)argSrc;
for (; argNSrcElem > 0; --argNSrcElem)
{
M_SCP_Msg_ClearNVMemory(argDataFunc, argDataFuncArg, src++);
}
}
This would be the expected output:
extern void M_SCP_Msg_ClearNVMemory(
Marshal_dataFunc* argDataFunc, Marshal_dataFuncArg argDataFuncArg, void const* argSrc);
extern void MA_SCP_Msg_ClearNVMemory(
Marshal_dataFunc* argDataFunc, Marshal_dataFuncArg argDataFuncArg,
void const* argSrc, unsigned argNSrcElem);
Currently, the lines of the original file are read in as strings which are assigned through a streamreader and then that string is later written to a streamwriter, so I thought iterating through and finding any strings containing any functions would be a good place to start, and once I have those strings I could edit them somehow. This is what I have so far, finList being the list of strings and fin being the string I will write to the output file.
List<string> finList = new List<string>();
finList.AddRange(fin.Split('\n'));
for (int x = 0; x < finList.Count; x++)
{
if (finList[x] == "void" || finList[x] == "_Bool" || finList[x] == "bool" || finList[x] == "unsigned")
{
finList[x] = im not sure what to do here
fin = string.Empty;
}
}
for (int x = 0; x < finList.Count; x++)
{
fin += finList[x];
}
Any direction or help would be much appreciated. I am relatively new to C# and C, so please be patient if I am not using the correct terms for anything. I think ending the string/line of the function at the ")" is what makes the most sense, but I am unsure how to do this.
Thanks in advance!
Quick and dirty solution would be something like this:
int bracketLevel = 0;
int squareBracketLevel = 0;
var methods = new List<string>();
var isMethodMode = true; // track if we are in method definition or in method body
var isMethod = false; // if we have seen parenthesis in definition
var builder = new StringBuilder();
for (int i = 0; i < fin.Length; i++)
{
if (isMethodMode)
{
switch (fin[i])
{
case '(':
isMethod = true;
builder.Append(fin[i]);
bracketLevel++;
break;
case ')':
builder.Append(fin[i]);
bracketLevel--;
break;
case '{':
if (bracketLevel > 0) continue;
if (isMethod)
{
methods.Add(builder.ToString().Trim());
builder.Clear();
isMethod = false;
}
isMethodMode = false;
squareBracketLevel++;
break;
default:
builder.Append(fin[i]);
break;
}
}
else
{
switch (fin[i])
{
case '{':
squareBracketLevel++;
break;
case '}':
squareBracketLevel--;
if (squareBracketLevel == 0)
{
isMethodMode = true;
}
break;
}
}
}
Variable fin contains loaded C file. While this works for your example there are couple of assumptions:
C code is valid (no mismatched parenthesis)
No comments which would contain parenthesis (this includes commented out functions as was already noted in comments)
Body block does not contain curly braces in string constants
If those assumptions do not hold for you, then you will have to take a look into parser generators which will parse C file and generate abstract syntax tree for you from which you can extract desired information. One example is ANTLR. C grammar is also available at C.g4.
Ok, so a friend of mine asked me to help him out with a string reverse method that can be reused without using String.Reverse (it's a homework assignment for him). Now, I did, below is the code. It works. Splendidly actually. Obviously by looking at it you can see the larger the string the longer the time it takes to work. However, my question is WHY does it work? Programming is a lot of trial and error, and I was more pseudocoding than actual coding and it worked lol.
Can someone explain to me how exactly reverse = ch + reverse; is working? I don't understand what is making it go into reverse :/
class Program
{
static void Reverse(string x)
{
string text = x;
string reverse = string.Empty;
foreach (char ch in text)
{
reverse = ch + reverse;
// this shows the building of the new string.
// Console.WriteLine(reverse);
}
Console.WriteLine(reverse);
}
static void Main(string[] args)
{
string comingin;
Console.WriteLine("Write something");
comingin = Console.ReadLine();
Reverse(comingin);
// pause
Console.ReadLine();
}
}
If the string passed through is "hello", the loop will be doing this:
reverse = 'h' + string.Empty
reverse = 'e' + 'h'
reverse = 'l' + 'eh'
until it's equal to
olleh
If your string is My String, then:
Pass 1, reverse = 'M'
Pass 2, reverse = 'yM'
Pass 3, reverse = ' yM'
You're taking each char and saying "that character and tack on what I had before after it".
I think your question has been answered. My reply goes beyond the immediate question and more to the spirit of the exercise. I remember having this task many decades ago in college, when memory and mainframe (yikes!) processing time was at a premium. Our task was to reverse an array or string, which is an array of characters, without creating a 2nd array or string. The spirit of the exercise was to teach one to be mindful of available resources.
In .NET, a string is an immutable object, so I must use a 2nd string. I wrote up 3 more examples to demonstrate different techniques that may be faster than your method, but which shouldn't be used to replace the built-in .NET Replace method. I'm partial to the last one.
// StringBuilder inserting at 0 index
public static string Reverse2(string inputString)
{
var result = new StringBuilder();
foreach (char ch in inputString)
{
result.Insert(0, ch);
}
return result.ToString();
}
// Process inputString backwards and append with StringBuilder
public static string Reverse3(string inputString)
{
var result = new StringBuilder();
for (int i = inputString.Length - 1; i >= 0; i--)
{
result.Append(inputString[i]);
}
return result.ToString();
}
// Convert string to array and swap pertinent items
public static string Reverse4(string inputString)
{
var chars = inputString.ToCharArray();
for (int i = 0; i < (chars.Length/2); i++)
{
var temp = chars[i];
chars[i] = chars[chars.Length - 1 - i];
chars[chars.Length - 1 - i] = temp;
}
return new string(chars);
}
Please imagine that you entrance string is "abc". After that you can see that letters are taken one by one and add to the start of the new string:
reverse = "", ch='a' ==> reverse (ch+reverse) = "a"
reverse= "a", ch='b' ==> reverse (ch+reverse) = b+a = "ba"
reverse= "ba", ch='c' ==> reverse (ch+reverse) = c+ba = "cba"
To test the suggestion by Romoku of using StringBuilder I have produced the following code.
public static void Reverse(string x)
{
string text = x;
string reverse = string.Empty;
foreach (char ch in text)
{
reverse = ch + reverse;
}
Console.WriteLine(reverse);
}
public static void ReverseFast(string x)
{
string text = x;
StringBuilder reverse = new StringBuilder();
for (int i = text.Length - 1; i >= 0; i--)
{
reverse.Append(text[i]);
}
Console.WriteLine(reverse);
}
public static void Main(string[] args)
{
int abcx = 100; // amount of abc's
string abc = "";
for (int i = 0; i < abcx; i++)
abc += "abcdefghijklmnopqrstuvwxyz";
var x = new System.Diagnostics.Stopwatch();
x.Start();
Reverse(abc);
x.Stop();
string ReverseMethod = "Reverse Method: " + x.ElapsedMilliseconds.ToString();
x.Restart();
ReverseFast(abc);
x.Stop();
Console.Clear();
Console.WriteLine("Method | Milliseconds");
Console.WriteLine(ReverseMethod);
Console.WriteLine("ReverseFast Method: " + x.ElapsedMilliseconds.ToString());
System.Console.Read();
}
On my computer these are the speeds I get per amount of alphabet(s).
100 ABC(s)
Reverse ~5-10ms
FastReverse ~5-15ms
1000 ABC(s)
Reverse ~120ms
FastReverse ~20ms
10000 ABC(s)
Reverse ~16,852ms!!!
FastReverse ~262ms
These time results will vary greatly depending on the computer but one thing is for certain if you are processing more than 100k characters you are insane for not using StringBuilder! On the other hand if you are processing less than 2000 characters the overhead from the StringBuilder definitely seems to catch up with its performance boost.
i want to find a efficent way to do :
i have a string like :
'1,2,5,11,33'
i want to pad zero only to the numbers that below 10 (have one digit)
so i want to get
'01,02,05,11,33'
thanks
How much do you really care about efficiency? Personally I'd use:
string padded = string.Join(",", original.Split(',')
.Select(x => x.PadLeft(2, '0')));
(As pointed out in the comments, if you're using .NET 3.5 you'll need a call to ToArray after the Select.)
That's definitely not the most efficient solution, but it's what I would use until I'd proved that it wasn't efficient enough. Here's an alternative...
// Make more general if you want, with parameters for the separator, length etc
public static string PadCommaSeparated(string text)
{
StringBuilder builder = new StringBuilder();
int start = 0;
int nextComma = text.IndexOf(',');
while (nextComma >= 0)
{
int itemLength = nextComma - start;
switch (itemLength)
{
case 0:
builder.Append("00,");
break;
case 1:
builder.Append("0");
goto default;
default:
builder.Append(text, start, itemLength);
builder.Append(",");
break;
}
start = nextComma + 1;
nextComma = text.IndexOf(',', start);
}
// Now deal with the end...
int finalItemLength = text.Length - start;
switch (finalItemLength)
{
case 0:
builder.Append("00");
break;
case 1:
builder.Append("0");
goto default;
default:
builder.Append(text, start, finalItemLength);
break;
}
return builder.ToString();
}
It's horrible code, but I think it will do what you want...
string input= "1,2,3,11,33";
string[] split = string.Split(input);
List<string> outputList = new List<string>();
foreach(var s in split)
{
outputList.Add(s.PadLeft(2, '0'));
}
string output = string.Join(outputList.ToArray(), ',');
What is the best way to convert from Pascal Case (upper Camel Case) to a sentence.
For example starting with
"AwaitingFeedback"
and converting that to
"Awaiting feedback"
C# preferable but I could convert it from Java or similar.
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}
In versions of visual studio after 2015, you can do
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => $"{m.Value[0]} {char.ToLower(m.Value[1])}");
}
Based on: Converting Pascal case to sentences using regular expression
I will prefer to use Humanizer for this. Humanizer is a Portable Class Library that meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities.
Short Answer
"AwaitingFeedback".Humanize() => Awaiting feedback
Long and Descriptive Answer
Humanizer can do a lot more work other examples are:
"PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence"
"Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence"
"Can_return_title_Case".Humanize(LetterCasing.Title) => "Can Return Title Case"
"CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case"
Complete code is :
using Humanizer;
using static System.Console;
namespace HumanizerConsoleApp
{
class Program
{
static void Main(string[] args)
{
WriteLine("AwaitingFeedback".Humanize());
WriteLine("PascalCaseInputStringIsTurnedIntoSentence".Humanize());
WriteLine("Underscored_input_string_is_turned_into_sentence".Humanize());
WriteLine("Can_return_title_Case".Humanize(LetterCasing.Title));
WriteLine("CanReturnLowerCase".Humanize(LetterCasing.LowerCase));
}
}
}
Output
Awaiting feedback
Pascal case input string is turned into sentence
Underscored input string is turned into sentence Can Return Title Case
can return lower case
If you prefer to write your own C# code you can achieve this by writing some C# code stuff as answered by others already.
Here you go...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CamelCaseToString
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CamelCaseToString("ThisIsYourMasterCallingYou"));
}
private static string CamelCaseToString(string str)
{
if (str == null || str.Length == 0)
return null;
StringBuilder retVal = new StringBuilder(32);
retVal.Append(char.ToUpper(str[0]));
for (int i = 1; i < str.Length; i++ )
{
if (char.IsLower(str[i]))
{
retVal.Append(str[i]);
}
else
{
retVal.Append(" ");
retVal.Append(char.ToLower(str[i]));
}
}
return retVal.ToString();
}
}
}
This works for me:
Regex.Replace(strIn, "([A-Z]{1,2}|[0-9]+)", " $1").TrimStart()
This is just like #SSTA, but is more efficient than calling TrimStart.
Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")
Found this in the MvcContrib source, doesn't seem to be mentioned here yet.
return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
Just because everyone has been using Regex (except this guy), here's an implementation with StringBuilder that was about 5x faster in my tests. Includes checking for numbers too.
"SomeBunchOfCamelCase2".FromCamelCaseToSentence == "Some Bunch Of Camel Case 2"
public static string FromCamelCaseToSentence(this string input) {
if(string.IsNullOrEmpty(input)) return input;
var sb = new StringBuilder();
// start with the first character -- consistent camelcase and pascal case
sb.Append(char.ToUpper(input[0]));
// march through the rest of it
for(var i = 1; i < input.Length; i++) {
// any time we hit an uppercase OR number, it's a new word
if(char.IsUpper(input[i]) || char.IsDigit(input[i])) sb.Append(' ');
// add regularly
sb.Append(input[i]);
}
return sb.ToString();
}
Here's a basic way of doing it that I came up with using Regex
public static string CamelCaseToSentence(this string value)
{
var sb = new StringBuilder();
var firstWord = true;
foreach (var match in Regex.Matches(value, "([A-Z][a-z]+)|[0-9]+"))
{
if (firstWord)
{
sb.Append(match.ToString());
firstWord = false;
}
else
{
sb.Append(" ");
sb.Append(match.ToString().ToLower());
}
}
return sb.ToString();
}
It will also split off numbers which I didn't specify but would be useful.
string camel = "MyCamelCaseString";
string s = Regex.Replace(camel, "([A-Z])", " $1").ToLower().Trim();
Console.WriteLine(s.Substring(0,1).ToUpper() + s.Substring(1));
Edit: didn't notice your casing requirements, modifed accordingly. You could use a matchevaluator to do the casing, but I think a substring is easier. You could also wrap it in a 2nd regex replace where you change the first character
"^\w"
to upper
\U (i think)
I'd use a regex, inserting a space before each upper case character, then lowering all the string.
string spacedString = System.Text.RegularExpressions.Regex.Replace(yourString, "\B([A-Z])", " \k");
spacedString = spacedString.ToLower();
It is easy to do in JavaScript (or PHP, etc.) where you can define a function in the replace call:
var camel = "AwaitingFeedbackDearMaster";
var sentence = camel.replace(/([A-Z].)/g, function (c) { return ' ' + c.toLowerCase(); });
alert(sentence);
Although I haven't solved the initial cap problem... :-)
Now, for the Java solution:
String ToSentence(String camel)
{
if (camel == null) return ""; // Or null...
String[] words = camel.split("(?=[A-Z])");
if (words == null) return "";
if (words.length == 1) return words[0];
StringBuilder sentence = new StringBuilder(camel.length());
if (words[0].length() > 0) // Just in case of camelCase instead of CamelCase
{
sentence.append(words[0] + " " + words[1].toLowerCase());
}
else
{
sentence.append(words[1]);
}
for (int i = 2; i < words.length; i++)
{
sentence.append(" " + words[i].toLowerCase());
}
return sentence.toString();
}
System.out.println(ToSentence("AwaitingAFeedbackDearMaster"));
System.out.println(ToSentence(null));
System.out.println(ToSentence(""));
System.out.println(ToSentence("A"));
System.out.println(ToSentence("Aaagh!"));
System.out.println(ToSentence("stackoverflow"));
System.out.println(ToSentence("disableGPS"));
System.out.println(ToSentence("Ahh89Boo"));
System.out.println(ToSentence("ABC"));
Note the trick to split the sentence without loosing any character...
Pseudo-code:
NewString = "";
Loop through every char of the string (skip the first one)
If char is upper-case ('A'-'Z')
NewString = NewString + ' ' + lowercase(char)
Else
NewString = NewString + char
Better ways can perhaps be done by using regex or by string replacement routines (replace 'X' with ' x')
An xquery solution that works for both UpperCamel and lowerCamel case:
To output sentence case (only the first character of the first word is capitalized):
declare function content:sentenceCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),lower-case(replace($remainingCharacters, '([A-Z])', ' $1')))
};
To output title case (first character of each word capitalized):
declare function content:titleCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),replace($remainingCharacters, '([A-Z])', ' $1'))
};
Found myself doing something similar, and I appreciate having a point-of-departure with this discussion. This is my solution, placed as an extension method to the string class in the context of a console application.
using System;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string piratese = "avastTharMatey";
string ivyese = "CheerioPipPip";
Console.WriteLine("{0}\n{1}\n", piratese.CamelCaseToString(), ivyese.CamelCaseToString());
Console.WriteLine("For Pete\'s sake, man, hit ENTER!");
string strExit = Console.ReadLine();
}
}
public static class StringExtension
{
public static string CamelCaseToString(this string str)
{
StringBuilder retVal = new StringBuilder(32);
if (!string.IsNullOrEmpty(str))
{
string strTrimmed = str.Trim();
if (!string.IsNullOrEmpty(strTrimmed))
{
retVal.Append(char.ToUpper(strTrimmed[0]));
if (strTrimmed.Length > 1)
{
for (int i = 1; i < strTrimmed.Length; i++)
{
if (char.IsUpper(strTrimmed[i])) retVal.Append(" ");
retVal.Append(char.ToLower(strTrimmed[i]));
}
}
}
}
return retVal.ToString();
}
}
}
Most of the preceding answers split acronyms and numbers, adding a space in front of each character. I wanted acronyms and numbers to be kept together so I have a simple state machine that emits a space every time the input transitions from one state to the other.
/// <summary>
/// Add a space before any capitalized letter (but not for a run of capitals or numbers)
/// </summary>
internal static string FromCamelCaseToSentence(string input)
{
if (string.IsNullOrEmpty(input)) return String.Empty;
var sb = new StringBuilder();
bool upper = true;
for (var i = 0; i < input.Length; i++)
{
bool isUpperOrDigit = char.IsUpper(input[i]) || char.IsDigit(input[i]);
// any time we transition to upper or digits, it's a new word
if (!upper && isUpperOrDigit)
{
sb.Append(' ');
}
sb.Append(input[i]);
upper = isUpperOrDigit;
}
return sb.ToString();
}
And here's some tests:
[TestCase(null, ExpectedResult = "")]
[TestCase("", ExpectedResult = "")]
[TestCase("ABC", ExpectedResult = "ABC")]
[TestCase("abc", ExpectedResult = "abc")]
[TestCase("camelCase", ExpectedResult = "camel Case")]
[TestCase("PascalCase", ExpectedResult = "Pascal Case")]
[TestCase("Pascal123", ExpectedResult = "Pascal 123")]
[TestCase("CustomerID", ExpectedResult = "Customer ID")]
[TestCase("CustomABC123", ExpectedResult = "Custom ABC123")]
public string CanSplitCamelCase(string input)
{
return FromCamelCaseToSentence(input);
}
Mostly already answered here
Small chage to the accepted answer, to convert the second and subsequent Capitalised letters to lower case, so change
if (char.IsUpper(text[i]))
newText.Append(' ');
newText.Append(text[i]);
to
if (char.IsUpper(text[i]))
{
newText.Append(' ');
newText.Append(char.ToLower(text[i]));
}
else
newText.Append(text[i]);
Here is my implementation. This is the fastest that I got while avoiding creating spaces for abbreviations.
public static string PascalCaseToSentence(string input)
{
if (string.IsNullOrEmpty(input) || input.Length < 2)
return input;
var sb = new char[input.Length + ((input.Length + 1) / 2)];
var len = 0;
var lastIsLower = false;
for (int i = 0; i < input.Length; i++)
{
var current = input[i];
if (current < 97)
{
if (lastIsLower)
{
sb[len] = ' ';
len++;
}
lastIsLower = false;
}
else
{
lastIsLower = true;
}
sb[len] = current;
len++;
}
return new string(sb, 0, len);
}