Split string expression with multiple parenthesis (C#) - 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.

Related

Take only letters from the string and reverse them

I'm preparing for my interview, faced the problem with the task. The case is that we're having a string:
test12pop90java989python
I need to return new string where words will be reversed and numbers will stay in the same place:
test12pop90java989python ==> tset12pop90avaj989nohtyp
What I started with:
Transferring string to char array
Use for loop + Char.IsNumber
??
var charArray = test.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (!Char.IsNumber(charArray[i]))
{
....
}
}
but currently I'm stuck and don't know how to proceed, any tips how it can be done?
You can't reverse a run of letters until you've observed the entire run; until then, you need to keep track of the pending letters to be reversed and appended to the final output upon encountering a number or the end of the string. By storing these pending characters in a Stack<> they are naturally returned in the reverse order they were added.
static string Transform(string input)
{
StringBuilder outputBuilder = new StringBuilder(input.Length);
Stack<char> pending = new Stack<char>();
foreach (char c in input)
if (char.IsNumber(c))
{
// In the reverse order of which they were added, consume
// and append pending characters as long as they are available
while (pending.Count > 0)
outputBuilder.Append(pending.Pop());
// Alternatively...
//foreach (char p in pending)
// outputBuilder.Append(p);
//pending.Clear();
outputBuilder.Append(c);
}
else
pending.Push(c);
// Handle pending characters when input does not end with a number
while (pending.Count > 0)
outputBuilder.Append(pending.Pop());
return outputBuilder.ToString();
}
A similar but buffer-free way is to do it is to store the index of the start of the current run of letters, then walk back through and append each character when a number is found...
static string Transform(string input)
{
StringBuilder outputBuilder = new StringBuilder(input.Length);
int lettersStartIndex = -1;
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (char.IsNumber(c))
{
if (lettersStartIndex >= 0)
{
// Iterate backwards from the previous character to the start of the run
for (int j = i - 1; j >= lettersStartIndex; j--)
outputBuilder.Append(input[j]);
lettersStartIndex = -1;
}
outputBuilder.Append(c);
}
else if (lettersStartIndex < 0)
lettersStartIndex = i;
}
// Handle remaining characters when input does not end with a number
if (lettersStartIndex >= 0)
for (int j = input.Length - 1; j >= lettersStartIndex; j--)
outputBuilder.Append(input[j]);
return outputBuilder.ToString();
}
For both implementations, calling Transform() with...
string[] inputs = new string[] {
"test12pop90java989python",
"123test12pop90java989python321",
"This text contains no numbers",
"1a2b3c"
};
for (int i = 0; i < inputs.Length; i++)
{
string input = inputs[i];
string output = Transform(input);
Console.WriteLine($" Input[{i}]: \"{input }\"");
Console.WriteLine($"Output[{i}]: \"{output}\"");
Console.WriteLine();
}
...produces this output...
Input[0]: "test12pop90java989python"
Output[0]: "tset12pop90avaj989nohtyp"
Input[1]: "123test12pop90java989python321"
Output[1]: "123tset12pop90avaj989nohtyp321"
Input[2]: "This text contains no numbers"
Output[2]: "srebmun on sniatnoc txet sihT"
Input[3]: "1a2b3c"
Output[3]: "1a2b3c"
A possible solution using Regex and Linq:
using System;
using System.Text.RegularExpressions;
using System.Linq;
public class Program
{
public static void Main()
{
var result = "";
var matchList = Regex.Matches("test12pop90java989python", "([a-zA-Z]*)(\\d*)");
var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));
foreach (var el in list)
{
if (el.All(char.IsDigit))
{
result += el;
}
else
{
result += new string(el.Reverse().ToArray());
}
}
Console.WriteLine(result);
}
}
I've used code from stackoverflow.com/a/21123574/1037948 to create a list of Regex matches on line 11:
var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));
Hey you can do something like:
string test = "test12pop90java989python", tempStr = "", finalstr = "";
var charArray = test.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (!Char.IsNumber(charArray[i]))
{
tempStr += charArray[i];
}
else
{
char[] ReverseString = tempStr.Reverse().ToArray();
foreach (char charItem in ReverseString)
{
finalstr += charItem;
}
tempStr = "";
finalstr += charArray[i];
}
}
if(tempStr != "" && tempStr != null)
{
char[] ReverseString = tempStr.Reverse().ToArray();
foreach (char charItem in ReverseString)
{
finalstr += charItem;
}
tempStr = "";
}
I hope this helps

Changing commas within quotes

I am trying to read the data in a text file which is separated by commas. My problem, is that one of my data pieces has a comma within it. An example of what the text file looks like is:
a, b, "c, d", e, f.
I want to be able to take the comma between c and d and change it to a semicolon so that I can still use the string.Split() method.
using (StreamReader reader = new StreamReader("file.txt"))
{
string line;
while ((line = reader.ReadLine ()) != null) {
bool firstQuote = false;
for (int i = 0; i < line.Length; i++)
{
if (line [i] == '"' )
{
firstQuote = true;
}
else if (firstQuote == true)
{
if (line [i] == '"')
{
break;
}
if ((line [i] == ','))
{
line = line.Substring (0, i) + ";" + line.Substring (i + 1, (line.Length - 1) - i);
}
}
}
Console.WriteLine (line);
}
I am having a problem. Instead of producing
a, b, "c; d", e, f
it is producing
a, b, "c; d"; e; f
It is replacing all of the following commas with semicolons instead of just the comma in the quotes. Can anybody help me fix my existing code?
Basically if you find a closing " you recognize it as it was an opening quote.
Change the line:
firstQuote = true;
to
firstQuote = !firstQuote;
and it should work.
You need to reset firstquote to false after you hit the second quote.
else if (firstQuote == true) {
if (line [i] == '"') {
firstquote = false;
break;
}
Here is a simple application to get the required result
static void Main(string[] args)
{
String str = "a,b,\"c,d\",e,f,\"g,h\",i,j,k,l,\"m,n,o\"";
int firstQuoteIndex = 0;
int secodQuoteIndex = 0;
Console.WriteLine(str);
bool iteration = false;
//String manipulation
//if count is even then count/2 is the number of pairs of double quotes we are having
//so we have to traverse count/2 times.
int count = str.Count(s => s.Equals('"'));
if (count >= 2)
{
firstQuoteIndex = str.IndexOf("\"");
for (int i = 0; i < count / 2; i++)
{
if (iteration)
{
firstQuoteIndex = str.IndexOf("\"", firstQuoteIndex + 1);
}
secodQuoteIndex = str.IndexOf("\"", firstQuoteIndex + 1);
string temp = str.Substring(firstQuoteIndex + 1, secodQuoteIndex - (firstQuoteIndex + 1));
firstQuoteIndex = secodQuoteIndex + 1;
if (count / 2 > 1)
iteration = true;
string temp2= temp.Replace(',', ';');
str = str.Replace(temp, temp2);
Console.WriteLine(temp);
}
}
Console.WriteLine(str);
Console.ReadLine();
}
Please feel free to ask in case of doubt
string line = "a,b,mc,dm,e,f,mk,lm,g,h";
string result =replacestr(line, 'm', ',', ';');
public string replacestr(string line,char seperator,char oldchr,char newchr)
{
int cnt = 0;
StringBuilder b = new StringBuilder();
foreach (char chr in line)
{
if (cnt == 1 && chr == seperator)
{
b[b.ToString().LastIndexOf(oldchr)] = newchr;
b.Append(chr);
cnt = 0;
}
else
{
if (chr == seperator)
cnt = 1;
b.Append(chr);
}
}
return b.ToString();
}

Bracket Checker Using Stack and Queue in C#

I am having an issue solving Bracket Checker .
i cant seem to solve the problem if user input this sequence of bracket then my program must print its not a right sequence
Input:
({}[)
Output:
Not a Right Sequence
My code is below
Stack s = new Stack();
Queue q = new Queue();
bool isok = true;
string FinalData = "0";
Console.WriteLine("Enter Brackets");
string data = Console.ReadLine();
for (int i = 0; i < data.Length; i++)
{
if (data.Substring(i, 1) == "{"
|| data.Substring(i, 1) == "["
|| data.Substring(i, 1) == "("
)
{
s.Push(data.Substring(i, 1));
}
else
{
q.Enqueue(data.Substring(i, 1));
}
}
while (s.Count > 0 && q.Count > 0)
{
FinalData = (String)s.Pop();
string value = (String)q.Dequeue();
if (FinalData == value)
{
isok = false;
break;
}
}
if (isok)
Console.WriteLine(data + " is a Right Sequence.");
else
Console.WriteLine(data + " is Not a Right Sequence.");
Console.ReadLine();
}
I'l give you a few hints and the basic idea:
you don't need the Queue, just a Stack<char>.
read the input, for each char:
if the char is an open brace, push it
if the char is a close brace, pop the stack and compare.
discard other chars
boolean isCorrect;
public boolean checkBraces(String braces)
{
Stack<Character>stack = new Stack<Character>();
int openBCount = 0;
int closeBCount = 0;
for(int c = 0; c<=braces.length()-1; c++)
{
//check for open braces push to stack
if(braces.charAt(c)=='{' || braces.charAt(c)=='[' ||braces.charAt(c)=='(')
{
stack.push(braces.charAt(c));
openBCount++;
} ////check for close braces. pop the open braces
//compare it to the closed braces using the the
//method ValidatePerBraces
//therefor checking for CORRECTNEES of how the braces //are closed
else if(braces.charAt(c)=='}' || braces.charAt(c)==']' || braces.charAt(c)==')')
{
closeBCount++;
if(!ValidatePerBraces(stack.pop(), braces.charAt(c)))
{
isCorrect = false; //return false in case where they dont match
return isCorrect;
}
}
//for braces to be complete, open and close braces
//should be even, if they are not even then it is
//for sure wrong at least for the specification.
if(c>=braces.length()-1)
{
if(openBCount != closeBCount)
{
isCorrect = false;
return isCorrect;
}
}
}
isCorrect = true; // true if they all match
return isCorrect;
}
// returns true if validated
public boolean ValidatePerBraces(char a, char b)
{
return a == '(' && b== ')' || a == '[' && b == ']' || a == '{' && b== '}' ;
}
public bool CheckBraces(string data)
{
Stack<char> stack = new Stack<char>();
foreach(char c in data){
switch(c){
case '(':
case '[':
case '{':
stack.Push(c);
break;
case ')':
case ']':
case '}':
if(!CheckMatch(stack.Pop(),c)){
return false;
}
break;
}
}
return true;
}
private bool CheckMatch(char a, char b){
return a=='(' && b==')' ||
a=='[' && b==']' ||
a=='{' && b=='}';
}
Thannks Guys I have Solved The Problem Using stack And Queue Both AT the Same time. Here's the code
Stack s = new Stack();
Queue q = new Queue();
bool isRight = true;
char OpeningBracket = ' ';
char closingBracket = ' ';
Console.WriteLine("Enter Brackets");
string data = Console.ReadLine();
char[] character = data.ToCharArray();
for (int i = 0; i < character.Length; i++)
{
if (character[i] == '(' || character[i] == '{' ||
character[i] == '[')
{
s.Push(character[i]);
}
else
q.Enqueue(character[i]);
}
if (s.Count == 0 || q.Count == 0)
isRight = false;
while (s.Count > 0 && q.Count > 0)
{
OpeningBracket = (char)s.Pop();
closingBracket = (char)q.Dequeue();
if ((OpeningBracket == '(' && closingBracket != ')')
|| (OpeningBracket == '[' && closingBracket != ']')
|| (OpeningBracket == '{' && closingBracket != '}')
)
{
isRight = false;
}
}
if (isRight)
Console.WriteLine(data + " is a Right Sequence.");
else
Console.WriteLine(data + " is Not Right Sequence.");
Console.ReadLine();
}
private static bool IsCorrectBracketSeq(string sequence)
{
var stack = new Stack<char>();
foreach (var sign in sequence)
{
if(sign == '(' || sign == '[' || sign == '{')
stack.Push(sign);
else if (sign == ')' || sign == ']' || sign == '}')
{
if (!stack.Any())
return false;
var topSing = stack.Pop();
var str = $"{topSing}{sign}";
if (str != "[]" && str != "{}" && str != "()")
return false;
}
}
return stack.Count == 0;
}
static bool IsBracesValidator(string input)
{
bool IsValidBraces = true;
char[] chrArray = input.ToCharArray();
List<Char> foundOpenParanthesis = new List<char>();
List<Char> foundClosedParanthesis = new List<char>();
char[] chrOpenParanthesis = { '{', '[', '(', '<' };
char[] chrClosedParanthesis = { '}', ']', ')', '>' };
for (int i = 0; i <= chrArray.Length - 1; i++)
{
if (chrOpenParanthesis.Contains(chrArray[i]))
{
foundOpenParanthesis.Add(chrArray[i]);
}
if (chrClosedParanthesis.Contains(chrArray[i]))
{
foundClosedParanthesis.Add(chrArray[i]);
}
}
if (foundOpenParanthesis.Count == foundClosedParanthesis.Count)
{
for(int i=0;i< foundOpenParanthesis.Count;i++)
{
char chr = foundOpenParanthesis[i];
switch (chr)
{
case '[': chr = ']'; break;
case '<': chr = '>'; break;
case '(': chr = ')'; break;
case '{': chr = '}'; break;
}
if (!chr.Equals(foundClosedParanthesis[foundClosedParanthesis.Count - i-1]))
{
IsValidBraces = false;
break;
}
}
} else
{
IsValidBraces = false;
}
return IsValidBraces;
}

How to escape JSON string?

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)

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