How to escape JSON string? - c#

Are there any classes/functions available to be used for easy JSON escaping? I'd rather not have to write my own.

I use System.Web.HttpUtility.JavaScriptStringEncode
string quoted = HttpUtility.JavaScriptStringEncode(input);

For those using the very popular Json.Net project from Newtonsoft the task is trivial:
using Newtonsoft.Json;
....
var s = JsonConvert.ToString(#"a\b");
Console.WriteLine(s);
....
This code prints:
"a\\b"
That is, the resulting string value contains the quotes as well as the escaped backslash.

Building on the answer by Dejan, what you can do is import System.Web.Helpers .NET Framework assembly, then use the following function:
static string EscapeForJson(string s) {
string quoted = System.Web.Helpers.Json.Encode(s);
return quoted.Substring(1, quoted.Length - 2);
}
The Substring call is required, since Encode automatically surrounds strings with double quotes.

Yep, just add the following function to your Utils class or something:
public static string cleanForJSON(string s)
{
if (s == null || s.Length == 0) {
return "";
}
char c = '\0';
int i;
int len = s.Length;
StringBuilder sb = new StringBuilder(len + 4);
String t;
for (i = 0; i < len; i += 1) {
c = s[i];
switch (c) {
case '\\':
case '"':
sb.Append('\\');
sb.Append(c);
break;
case '/':
sb.Append('\\');
sb.Append(c);
break;
case '\b':
sb.Append("\\b");
break;
case '\t':
sb.Append("\\t");
break;
case '\n':
sb.Append("\\n");
break;
case '\f':
sb.Append("\\f");
break;
case '\r':
sb.Append("\\r");
break;
default:
if (c < ' ') {
t = "000" + String.Format("X", c);
sb.Append("\\u" + t.Substring(t.Length - 4));
} else {
sb.Append(c);
}
break;
}
}
return sb.ToString();
}

I have used following code to escape the string value for json.
You need to add your '"' to the output of the following code:
public static string EscapeStringValue(string value)
{
const char BACK_SLASH = '\\';
const char SLASH = '/';
const char DBL_QUOTE = '"';
var output = new StringBuilder(value.Length);
foreach (char c in value)
{
switch (c)
{
case SLASH:
output.AppendFormat("{0}{1}", BACK_SLASH, SLASH);
break;
case BACK_SLASH:
output.AppendFormat("{0}{0}", BACK_SLASH);
break;
case DBL_QUOTE:
output.AppendFormat("{0}{1}",BACK_SLASH,DBL_QUOTE);
break;
default:
output.Append(c);
break;
}
}
return output.ToString();
}

In .Net Core 3+ and .Net 5+:
string escapedJsonString = JsonEncodedText.Encode(jsonString);

The methods offered here are faulty.
Why venture that far when you could just use System.Web.HttpUtility.JavaScriptEncode ?
If you're on a lower framework, you can just copy paste it from mono
Courtesy of the mono-project #
https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs
public static string JavaScriptStringEncode(string value, bool addDoubleQuotes)
{
if (string.IsNullOrEmpty(value))
return addDoubleQuotes ? "\"\"" : string.Empty;
int len = value.Length;
bool needEncode = false;
char c;
for (int i = 0; i < len; i++)
{
c = value[i];
if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92)
{
needEncode = true;
break;
}
}
if (!needEncode)
return addDoubleQuotes ? "\"" + value + "\"" : value;
var sb = new System.Text.StringBuilder();
if (addDoubleQuotes)
sb.Append('"');
for (int i = 0; i < len; i++)
{
c = value[i];
if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
sb.AppendFormat("\\u{0:x4}", (int)c);
else switch ((int)c)
{
case 8:
sb.Append("\\b");
break;
case 9:
sb.Append("\\t");
break;
case 10:
sb.Append("\\n");
break;
case 12:
sb.Append("\\f");
break;
case 13:
sb.Append("\\r");
break;
case 34:
sb.Append("\\\"");
break;
case 92:
sb.Append("\\\\");
break;
default:
sb.Append(c);
break;
}
}
if (addDoubleQuotes)
sb.Append('"');
return sb.ToString();
}
This can be compacted into
// https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
public class SimpleJSON
{
private static bool NeedEscape(string src, int i)
{
char c = src[i];
return c < 32 || c == '"' || c == '\\'
// Broken lead surrogate
|| (c >= '\uD800' && c <= '\uDBFF' &&
(i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'))
// Broken tail surrogate
|| (c >= '\uDC00' && c <= '\uDFFF' &&
(i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'))
// To produce valid JavaScript
|| c == '\u2028' || c == '\u2029'
// Escape "</" for <script> tags
|| (c == '/' && i > 0 && src[i - 1] == '<');
}
public static string EscapeString(string src)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
int start = 0;
for (int i = 0; i < src.Length; i++)
if (NeedEscape(src, i))
{
sb.Append(src, start, i - start);
switch (src[i])
{
case '\b': sb.Append("\\b"); break;
case '\f': sb.Append("\\f"); break;
case '\n': sb.Append("\\n"); break;
case '\r': sb.Append("\\r"); break;
case '\t': sb.Append("\\t"); break;
case '\"': sb.Append("\\\""); break;
case '\\': sb.Append("\\\\"); break;
case '/': sb.Append("\\/"); break;
default:
sb.Append("\\u");
sb.Append(((int)src[i]).ToString("x04"));
break;
}
start = i + 1;
}
sb.Append(src, start, src.Length - start);
return sb.ToString();
}
}

I ran speed tests on some of these answers for a long string and a short string. Clive Paterson's code won by a good bit, presumably because the others are taking into account serialization options. Here are my results:
Apple Banana
System.Web.HttpUtility.JavaScriptStringEncode: 140ms
System.Web.Helpers.Json.Encode: 326ms
Newtonsoft.Json.JsonConvert.ToString: 230ms
Clive Paterson: 108ms
\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\"things\to\escape\some\long\path\with\lots"\of\things\to\escape
System.Web.HttpUtility.JavaScriptStringEncode: 2849ms
System.Web.Helpers.Json.Encode: 3300ms
Newtonsoft.Json.JsonConvert.ToString: 2827ms
Clive Paterson: 1173ms
And here is the test code:
public static void Main(string[] args)
{
var testStr1 = "Apple Banana";
var testStr2 = #"\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\""things\to\escape\some\long\path\with\lots""\of\things\to\escape";
foreach (var testStr in new[] { testStr1, testStr2 })
{
var results = new Dictionary<string,List<long>>();
for (var n = 0; n < 10; n++)
{
var count = 1000 * 1000;
var sw = Stopwatch.StartNew();
for (var i = 0; i < count; i++)
{
var s = System.Web.HttpUtility.JavaScriptStringEncode(testStr);
}
var t = sw.ElapsedMilliseconds;
results.GetOrCreate("System.Web.HttpUtility.JavaScriptStringEncode").Add(t);
sw = Stopwatch.StartNew();
for (var i = 0; i < count; i++)
{
var s = System.Web.Helpers.Json.Encode(testStr);
}
t = sw.ElapsedMilliseconds;
results.GetOrCreate("System.Web.Helpers.Json.Encode").Add(t);
sw = Stopwatch.StartNew();
for (var i = 0; i < count; i++)
{
var s = Newtonsoft.Json.JsonConvert.ToString(testStr);
}
t = sw.ElapsedMilliseconds;
results.GetOrCreate("Newtonsoft.Json.JsonConvert.ToString").Add(t);
sw = Stopwatch.StartNew();
for (var i = 0; i < count; i++)
{
var s = cleanForJSON(testStr);
}
t = sw.ElapsedMilliseconds;
results.GetOrCreate("Clive Paterson").Add(t);
}
Console.WriteLine(testStr);
foreach (var result in results)
{
Console.WriteLine(result.Key + ": " + Math.Round(result.Value.Skip(1).Average()) + "ms");
}
Console.WriteLine();
}
Console.ReadLine();
}

I would also recommend using the JSON.NET library mentioned, but if you have to escape unicode characters (e.g. \uXXXX format) in the resulting JSON string, you may have to do it yourself. Take a look at Converting Unicode strings to escaped ascii string for an example.

I nice one-liner, used JsonConvert as others have but added substring to remove the added quotes and backslash.
var escapedJsonString = JsonConvert.ToString(JsonString).Substring(1, JsonString.Length - 2);

What about System.Web.Helpers.Json.Encode(...) (see http://msdn.microsoft.com/en-us/library/system.web.helpers.json.encode(v=vs.111).aspx)?

String.Format("X", c);
That just outputs: X
Try this instead:
string t = ((int)c).ToString("X");
sb.Append("\\u" + t.PadLeft(4, '0'));

There's a Json library at Codeplex

I chose to use System.Web.Script.Serialization.JavaScriptSerializer.
I have a small static helper class defined as follows:
internal static partial class Serialization
{
static JavaScriptSerializer serializer;
static Serialization()
{
serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = Int32.MaxValue;
}
public static string ToJSON<T>(T obj)
{
return serializer.Serialize(obj);
}
public static T FromJSON<T>(string data)
{
if (Common.IsEmpty(data))
return default(T);
else
return serializer.Deserialize<T>(data);
}
}
To serialize anything I just call Serialization.ToJSON(itemToSerialize)
To deserialize I just call Serialization.FromJSON<T>(jsonValueOfTypeT)

Related

Convert a string to an array of strings in c#

Can I get an array of string with CRLF or LF or CR included, only with linq ?
I don't want to use a loop .
I have a string like this "Hello \r\n Stackverflow\n How are you doing \r", and i have to convert it to be like this
mystring[0] = "Hello \r\n"
mystring[1] = "Stackverflow\n"
mystring[2] = "How are you doing \r"
Any ideas ?
This is slightly complicated by the fact that we have to handle "\r", "\n" AND "\r\n". I'm assuming you don't need to handle "\n\r" - if you do, you'll have to add a case for it in the code below.
Obviously there are many ways to solve this; here's a low-level approach that doesn't use anything other than a basic loop:
public static IEnumerable<string> SplitByAndKeepLineSeparators(string input)
{
if (input.Length == 0)
yield break;
int i = 0, j = 0;
while (true)
{
if (i == input.Length - 1) // Last char?
{
yield return input.Substring(j, i - j + 1);
break;
}
switch (input[i])
{
case '\r' when input[i+1] == '\n':
yield return input.Substring(j, i - j + 2);
i += 2;
j = i;
break;
case '\r':
yield return input.Substring(j, i - j + 1);
j = ++i;
break;
case '\n':
yield return input.Substring(j, i - j + 1);
j = ++i;
break;
default:
++i;
break;
}
}
}
Note: If using an older version of C# you won't be able to use that kind of switch, so your code would have to be:
public static IEnumerable<string> SplitByAndKeepLineSeparators(string input)
{
if (input.Length == 0)
yield break;
int i = 0, j = 0;
while (true)
{
if (i == input.Length - 1) // Last char?
{
yield return input.Substring(j, i - j + 1);
break;
}
if (input[i] == '\r' && input[i + 1] == '\n')
{
yield return input.Substring(j, i - j + 2);
i += 2;
j = i;
}
else if (input[i] == '\r')
{
yield return input.Substring(j, i - j + 1);
j = ++i;
}
else if (input[i] == '\n')
{
yield return input.Substring(j, i - j + 1);
j = ++i;
}
else
{
++i;
}
}
}
Try the below line please:-
var arr = mystring.Split('\n');

What is the meaning of \uE0001.\uE000 in the decompiled source?

I'm using this proximity card scanner software to read my card for testing. They provide an SDK but it covers everything except desktop scanners, even though their software is able to read it fine. I noticed their software was coded in .NET and I was able to decompile it using JetBrains dotPeek. I'm very close to what I'm needing. I was able to fix the decompiled code except for these 3 lines. I'm unfamiliar with how to handle the encoding:
string[] array = ((IEnumerable<string>) ConfigurationManager.AppSettings.AllKeys).Where<string>((Func<string, bool>) (stg => stg.StartsWith(\uE0001.\uE000(27359)))).ToArray<string>();
string str = ((IEnumerable<string>) ConfigurationManager.AppSettings.AllKeys).Any<string>((Func<string, bool>) (stg => stg == \uE0001.\uE000(28615))) ? ConfigurationManager.AppSettings[\uE0001.\uE000(28615)] : directoryName;
assyTypeKey = index2.Replace(\uE0001.\uE000(28428), \uE0001.\uE000(28439));
I know they're Unicode characters but it's looking very foreign to me with that declaration next to it in parentheses. I'm not sure how to handle this.
Here's one of the functions. I know it's ugly but it's decompiled:
public static void LoadSubServices()
{
//SubServicesManager._logger.Info((object) \uE0001.\uE000(28243));
string[] array = ((IEnumerable<string>) ConfigurationManager.AppSettings.AllKeys).Where<string>((Func<string, bool>) (stg => stg.StartsWith(\uE0001.\uE000(27359)))).ToArray<string>();
label_2:
int num1 = 1;
while (true)
{
switch (num1)
{
case 0:
//SubServicesManager._logger.Error((object) \uE0001.\uE000(28270));
num1 = 2;
continue;
case 1:
if (array.Length == 0)
{
num1 = 0;
continue;
}
goto label_7;
case 2:
goto label_31;
default:
goto label_2;
}
}
label_7:
string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
//SubServicesManager._logger.InfoFormat(\uE0001.\uE000(28582), (object) directoryName);
string str = ((IEnumerable<string>) ConfigurationManager.AppSettings.AllKeys).Any<string>((Func<string, bool>) (stg => stg == \uE0001.\uE000(28615))) ? ConfigurationManager.AppSettings[\uE0001.\uE000(28615)] : directoryName;
label_9:
int num2 = 1;
while (true)
{
switch (num2)
{
case 0:
//SubServicesManager._logger.ErrorFormat(\uE0001.\uE000(28621), (object) str);
num2 = 2;
continue;
case 1:
if (!Directory.Exists(str))
{
num2 = 0;
continue;
}
goto label_14;
case 2:
goto label_6;
default:
goto label_9;
}
}
label_6:
return;
label_14:
label_33:
for (int index1 = 0; index1 < array.Length; ++index1)
{
label_17:
int num3 = 2;
string appSetting1 = null;
string appSetting2 = null;
ILoadableServer loadableServer = null;
string index2 = null;
string assyTypeKey = null;
while (true)
{
switch (num3)
{
case 0:
//SubServicesManager._logger.InfoFormat(\uE0001.\uE000(28419), (object) appSetting1);
num3 = 1;
continue;
case 1:
loadableServer = SubServicesManager.LoadSubServiceAssembly(appSetting1, str, appSetting2);
num3 = 5;
continue;
case 2:
index2 = array[index1];
num3 = 3;
continue;
case 3:
assyTypeKey = index2.Replace(\uE0001.\uE000(28428), \uE0001.\uE000(28439));
num3 = 6;
continue;
case 4:
//SubServicesManager._logger.ErrorFormat(\uE0001.\uE000(28442), (object) appSetting1);
num3 = 9;
continue;
case 5:
if (loadableServer == null)
{
num3 = 4;
continue;
}
goto label_29;
case 6:
appSetting2 = ConfigurationManager.AppSettings[index2];
num3 = 7;
continue;
case 7:
if (((IEnumerable<string>) ConfigurationManager.AppSettings.AllKeys).Any<string>((Func<string, bool>) (stg => stg == assyTypeKey)))
{
num3 = 8;
continue;
}
goto label_30;
case 8:
appSetting1 = ConfigurationManager.AppSettings[assyTypeKey];
num3 = 0;
continue;
case 9:
goto label_33;
default:
goto label_17;
}
}
label_29:
SubServicesManager._loadableServices.Add(loadableServer);
//SubServicesManager._logger.InfoFormat(\uE0001.\uE000(28496));
continue;
label_30:
return;
//SubServicesManager._logger.WarnFormat(\uE0001.\uE000(28525), (object) index2, (object) appSetting2);
}
return;
label_31:;
}

How to calculate output of Infix-Expression by using stacks in C#

I already found different solutions on Stackoverflow, but there were some things I didnĀ“t understand.
Whats the best method to calculate the Output of e.g.: ((1+(4*(2+3)))+((2+3)*(4*5))) ?
My method looks as following, but I know there are lots of mistakes in it:
public static int ComputeInfix(string infix) {
Stack<char> operatorstack = new Stack<char>();
Stack<int> operandstack = new Stack<int>();
for(int j = 0; j < infix.Length; j++) {
char c = infix[j];
if (c => 0 && c <= 9) {
operandstack.Push(c);
}
else if ((c == '+' || c == '*' || c == '/' || c == '-')) {
if (operatorstack.IsEmpty()) {
operatorstack.Push(c);
}
else {
if (operatorstack.Peek() != '*' || operatorstack.Peek() != '/') {
operatorstack.Push(c);
}
}
}
else if (c == '(') {
operatorstack.Push(c);
}
else if (c == ')') {
operatorstack.Pop();
}
}
return infix;
}
Now changed it to:
Stack<char> operatorstack = new Stack<char>();
Stack<char> operandstack = new Stack<char>();
for(int j = 0; j < infix.Length; j++) {
char c = infix[j];
if (c => '0' && c <= '9') {
operandstack.Push(c);
}
But get error:
Infix.cs(16,8): error CS0136: A local variable named c' cannot be
declared in this scope because it would give a different meaning to
c', which is already used in a `parent or current' scope to denote
something else
Since I spent the time to write it, here is my solution:
public static int ComputeInfix(string infix) {
var operatorstack = new Stack<char>();
var operandstack = new Stack<int>();
var precedence = new Dictionary<char, int> { { '(', 0 }, { '*', 1 }, { '/', 1 }, { '+', 2 }, { '-', 2 }, { ')', 3 } };
foreach (var ch in $"({infix})") {
switch (ch) {
case var digit when Char.IsDigit(digit):
operandstack.Push(Convert.ToInt32(digit.ToString()));
break;
case var op when precedence.ContainsKey(op):
var keepLooping = true;
while (keepLooping && operatorstack.Count > 0 && precedence[ch] > precedence[operatorstack.Peek()]) {
switch (operatorstack.Peek()) {
case '+':
operandstack.Push(operandstack.Pop() + operandstack.Pop());
break;
case '-':
operandstack.Push(-operandstack.Pop() + operandstack.Pop());
break;
case '*':
operandstack.Push(operandstack.Pop() * operandstack.Pop());
break;
case '/':
var divisor = operandstack.Pop();
operandstack.Push(operandstack.Pop() / divisor);
break;
case '(':
keepLooping = false;
break;
}
if (keepLooping)
operatorstack.Pop();
}
if (ch == ')')
operatorstack.Pop();
else
operatorstack.Push(ch);
break;
default:
throw new ArgumentException();
}
}
if (operatorstack.Count > 0 || operandstack.Count > 1)
throw new ArgumentException();
return operandstack.Pop();
}

Split string expression with multiple parenthesis (C#)

I have below string and I want to split it in such a way that both the parameters of the function fnGetDate could be separated.
Function:
"fnGetDate('d',-1+ cint(cbool(DatePart('w',Date())<=2)) + cint(cbool(DatePart('w',Date())=2)))"
Desired output (after split):
[0] fnGetDate(
[1] 'd'
[2] -1+ cint(cbool(DatePart('w',Date())<=2)) + cint(cbool(DatePart('w',Date())=2))
According to your comment, counting the number of opening and closing parenthesis is OK for you.
This example works for me:
string str = "fnGetDate('d',-1+ cint(cbool(DatePart('w',Date())<=2)) + cint(cbool(DatePart('w',Date())=2)))";
int parLevel = 0;
List<string> arguments = new List<string>();
string currentString = String.Empty;
foreach (char t in str)
{
switch (t)
{
case '(':
if (t == '(') parLevel++;
currentString += t;
if (parLevel == 1)
{
arguments.Add(currentString);
currentString = String.Empty;
}
break;
case ')':
if (t == ')') parLevel--;
if (parLevel > 0) currentString += t;
break;
case ',':
if (parLevel == 1)
{
arguments.Add(currentString);
currentString = String.Empty;
}
else
currentString += t;
break;
default:
currentString += t;
break;
}
}
if (!String.IsNullOrEmpty(currentString)) arguments.Add(currentString);
for (int i = 0; i < arguments.Count; i++)
Console.WriteLine("Argument {0}: {1}", i, arguments[i]);
IDEOne Working Demo.

Counting vowels using switch

I tried to design a program which counts the vowels in a sentence.
In my code, I used a foreach statement with the if/else if statement. I would like to convert these line of code using the switch statement
but I'm not really sure where to go. Do I need to add a new method? I would appreciate your help.
This is what I tried so far: I checked this one is very wrong. The case 1 for example needs to have a constant. I'm not sure what constant shall I use here.
foreach (char v in yourSentence)
{
switch (v)
{
case 1:
(v==ch1);
counta++;
j++;
break;
case 2:
(v==ch2);
counte++;
j++;
break;
case 3:
(v==ch3);
counti++;
j++;
break;
case 4:
(v==ch4);
counto++;
j++;
break;
case 5:
(v==ch3);
counti++;
j++;
break;
}
}
Another question: I tried to change the color of the display text in the listBox. Is that possible to have different colors? What I also tried here is the first 5 (listBox1.Items.Add) are violet. And the sum of the (listBox1.Items.Add) is blue. But it seems that it didn't change. Did I miss something here?
private void btnCount_Click(object sender, EventArgs e)
{
string yourSentence;
yourSentence = textBoxVowels.Text.ToLower().Trim();
char ch1 = 'a';
char ch2 = 'e';
char ch3 = 'i';
char ch4 = 'o';
char ch5 = 'u';
int counta = 0;
int counte = 0;
int counti = 0;
int counto = 0;
int countu = 0;
int j = counta + counte + counti + counto + countu;
foreach (char v in yourSentence)
{
if (v == ch1) { counta++; j++; }
else if (v == ch2) { counte++; j++; }
else if (v == ch3) { counti++; j++; }
else if (v == ch4) { counto++; j++; }
else if (v == ch5) { countu++; j++; }
}
listBox1.Items.Add("There are " + counta.ToString().Trim() + " a's in the sentence");
listBox1.Items.Add("There are " + counte.ToString().Trim() + " e's in the sentence");
listBox1.Items.Add("There are " + counti.ToString().Trim() + " i's in the sentence");
listBox1.Items.Add("There are " + counto.ToString().Trim() + " o's in the sentence");
listBox1.Items.Add("There are " + countu.ToString().Trim() + " u's in the sentence");
listBox1.Font = new Font("Arial", 12, FontStyle.Bold);
listBox1.ForeColor = Color.Violet;
listBox1.Items.Add("There are " + j.ToString().Trim() + " vowels in the sentence");
listBox1.ForeColor = Color.Blue;
}
private void btnClear_Click(object sender, EventArgs e)
{
textBoxVowels.Text = null;
listBox1.Items.Clear();
}
Or just simplify the whole problem by using a bit of LINQ. :)
public static int CountVowels(this string value)
{
const string vowels = "aeiou";
return value.Count(chr => vowels.Contains(char.ToLower(chr)));
}
The Count extension method is particularly well suited to this task. Also, notice the use of a string of all vowels to check each character - much simpler than a switch statement.
Note: It seems I missed the fact that you want to count each vowel individually. In this case, the LINQ becomes a bit more complicated (at least if you want to do it efficiently), but I shall leave that as an exercise for you. Regardless, a switch statement is probably a good way to learn the basics of C#.
Since you're probably curious about the switch statement anyway, the following code uses the correct syntax:
foreach (var chr in sentence)
{
switch (chr)
{
case 'a':
...
break;
case 'e':
...
break;
case 'i':
...
break;
case 'o':
...
case 'u':
...
break;
}
}
I think you misunderstood how 'switch/case' works. Just change them to this:
case 'a':
counta++;
j++;
break;
Case needs a constant value that should be compared to the current character.
Here's a more advanced solution:
public static Dictionary<char, int> CountLetters(string value, string letters)
{
var counts = letters.ToDictionary(c => c.ToString(), c => 0, StringComparer.OrdinalIgnoreCase);
var groups = from c in value
let s = c.ToString()
where counts.ContainsKey(s)
group s by s;
foreach(var g in groups)
counts[g.Key] = g.Count();
return counts;
}
Which you could use like this:
var letterCounts = CountLetters(yourSentence, "aeiou");
int countA = letterCounts["a"];
int countE = letterCounts["e"];
int countI = letterCounts["i"];
int countO = letterCounts["o"];
int countU = letterCounts["u"];
int total = countA + countE + countI + countO + countU;
Update: Just realized that a StringComparer won't work for char keys. Switching to string key - not as efficient as char, but easier than writing a case-insensitive char comparer. I prefer the comparer approach to doing some sort of ToLower/ToUpper on everything dictionary-related.
Please also check the other answers to your questions for many helpful tips. I'm just rewriting your first piece of example code from your question to probably let it do what you mean:
foreach (char v in yourSentence)
{
switch (v)
{
case 'a': counta++; j++; break;
case 'e': counte++; j++; break;
case 'i': counti++; j++; break;
case 'o': counto++; j++; break;
case 'u': countu++; j++; break;
}
}
You seem to want to increase one of the { counta, counte, counti, counto, countu } variables for the five specific vowels using the switch (right?) and also increase the j variable for each of the vowels.
Having given this answer, I would personally do something different altogether. Like the LINQ example given by Noldorin. Or something like this, as perhaps suggested by cherryalpha:
// create dictionary
var counts = new Dictionary<char,int>();
// initialize it for the vowels
foreach (char v in "aeiuo")
{
counts.Add(v, 0);
}
// count all characters in sentence
foreach (char v in yourSentence) {
if ( counts.ContainsKey(v) ) {
// increase count for known characters
counts[v]++;
} else {
// add new count for characters not seen previously
counts.Add(v,1);
}
}
// calculate your total number of vowels
j = counts['a'] + counts['e'] + counts['i'] + counts['o'] + counts['u'];
Quick warning, just in case: You would need a using System.Collection.Generic at the top of your source file that contains this code to make sure the generic Dictionary is known by its short name.
(And be aware that this code will not only give you vowel counts, but counts for all the other characters in yourSentence as well.)
const string VOWELS = "aeiou";
var str = "Lorem ipsum dolor sit amet";
var q = from ch in str
where VOWELS.Contains(ch)
group ch by ch into g
select g;
var dict = q.ToDictionary(_ => _.Key, _ => _.Count());
I faced a similar kind of problem in an interview. But I had to show my result in a level control instead of listbox control ... so i solved this problem like this:
protected void Button1_Click(object sender, EventArgs e)
{
string EnterString;
EnterString = TextBox1.Text;
char ch1 = 'a';
char ch2 = 'e';
char ch3 = 'i';
char ch4 = 'o';
char ch5 = 'u';
int counta = 0;
int counte = 0;
int counti = 0;
int counto = 0;
int countu = 0;
char ch6 = 'A';
char ch7 = 'E';
char ch8 = 'I';
char ch9 = 'O';
char ch10 = 'U';
int countA = 0;
int countE = 0;
int countI = 0;
int countO = 0;
int countU = 0;
int j = counta + counte + counti + counto + countu + countA + countE + countI + countO + countU;
foreach (char v in EnterString)
{
if (v == ch1) { counta++; j++; }
else if (v == ch2) { counte++; j++; }
else if (v == ch3) { counti++; j++; }
else if (v == ch4) { counto++; j++; }
else if (v == ch5) { countu++; j++; }
}
foreach (char v in EnterString)
{
if (v == ch6) { countA++; j++; }
else if (v == ch7) { countE++; j++; }
else if (v == ch8) { countI++; j++; }
else if (v == ch9) { countO++; j++; }
else if (v == ch10) { countU++; j++; }
}
Label1.Text = j.ToString();
}

Categories