I get the error of "Index was outside the bounds of the array", at this line " order.price = Convert.ToDouble(custOrder.Split('$')[1]); ", I have follow the video at here, http://www.youtube.com/watch?v=EbrGoUqbb-A, but I still get the error, I am newbie for C#
public struct Orders
{
public string item;
public double price;
}
const double TAX=0.06;
Orders order = new Orders();
static double subtotal=0;
static double totalTaxes=0;
static double total;
string finalBill = "FINAL BILL:\n";
private void getValues(string custOrder)
{
order.item = custOrder.Split('$')[0];
order.price = Convert.ToDouble(custOrder.Split('$')[1]);
listOutput.Items.Add("Price:" + order.price);
finalBill += "Ordered Item:" + order.item + "\nPrice:" + order.price.ToString("C2") + "\n";
updateBill();
}
private void updateBill()
{
subtotal += order.price;
total += order.price + (order.price * TAX);
totalTaxes += order.price * TAX;
listOutput.Items.Clear();
listOutput.Items.Add(finalBill);
listOutput.Items.Add("Subtotal:" + subtotal.ToString("C2"));
listOutput.Items.Add("Tax:" + totalTaxes.ToString("C2"));
listOutput.Items.Add("Total:" + total.ToString("C2"));
}
private void dropdownSelection(object sender, EventArgs e)
{
if (sender == comboBox1)
getValues(comboBox1.SelectedItem.ToString());
}
custOrder.Split('$')[1]
Stuff that into a variable and use your debugger. Looks like your string custOrder does not contain a '$' character, or it is the last character in the string.
the .Split method, when used on a string, it returns an array. The split parameter is a character that is used as the splitting point.
For example:
String x = "test$one";
var result = x.Split('$') // this returns an array ["test", "one"]
the arrays start their counting from zero, so
result[0] // is "test"
result[1] // is "one"
the splitting character is not included.
In your case, there is no dollar sign, so the split result will be an array with just one string, with the index 0. custOrder.Split('$')[1] does not exist.
Update your getValue method as follows
Check whether you split call really returns 2 array elements to get element of index=1.
Also check whether the returned value of index=1 is really of type double or not. else you will get another error for the string like "asdf$gf" or "asdf$"
private void getValues(string custOrder)
{
double num;
if (custOrder.Split('$').Count() > 1)
{
order.item = custOrder.Split('$')[0];
if (double.TryParse(custOrder.Split('$')[1], out num))
{
order.price = Convert.ToDouble(custOrder.Split('$')[1]);
listOutput.Items.Add("Price:" + order.price);
finalBill += "Ordered Item:" + order.item + "\nPrice:" + order.price.ToString("C2") + "\n";
updateBill();
}
}
}
your string does not contain the '$' text or it only contains 1 of them. try this instead:
string[] splits = custOrder.Split("$".ToCharArray());
if (1 == splits.Length)
order.item = Convert.ToDouble(splits[0]);
else
throw new Exception("Cannot find $ in the customer order");
Depending on what you want you also may have meant Convert.ToDouble(splits[0]); as arrays use zero based indexing not 1 based indexing.
EDIT: changed code based on questioner providing input data sample.
Related
Hi I am just trying to add a zero to a number that is a string, for example, a company has some old barcodes in the system that was printed with only 12 characaters their new barcodes is 13 I just simply have to add an extra zero when its 12 in length.
using System;
public class Program
{
public static void Main()
{
string BarCode="000001661705";
char pad = '0';
if(BarCode.Length==12)
{
BarCode = BarCode.PadLeft(1, pad);
}
Console.WriteLine("Length of barcode" + BarCode.Length);
Console.WriteLine("Barcode=" + BarCode);
}
}
Here is the .net fillddle you will see the number of characters is still 12 when it should be 13 with the added zero on it.
https://dotnetfiddle.net/VsvPIl
Just add it as a string?
using System;
public class Program
{
public static void Main()
{
string BarCode="000001661705";
char pad = '0';
if(BarCode.Length==12)
{
BarCode = pad + BarCode;
}
Console.WriteLine("Length of barcode" + BarCode.Length);
Console.WriteLine("Barcode=" + BarCode);
}
}
You have to use BarCode.PadLeft(BarCode.Length + 1, pad) to get the desired output.
But I don't understand why you would want to do that, just add "0" + BarCode
PadLeft accepts as an argument totalWidth of returned string, so it pads if string is shorter and does nothing when length is already equal to o greater. Just use:
BarCode = BarCode.PadLeft(13, pad);
instead of
if(BarCode.Length==12)
{
// here is the problem, you specified totalWidth = 1
BarCode = BarCode.PadLeft(1, pad);
}
String.PadLeft Method
I am using this calculate function
private void Calculate()
{
double.TryParse(textBox1.Text, out num);
for (int a = 1; a <= 10; a++)
{
listBox1.Items.Add(a + " * " + num + "\n = " + a * num);
}
}
Putting Calculate() inside private void textBox1_TextChanged so it will autocalculate
I am also using :
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back)
{
listBox1.Items.Clear();
}
}
This works but if i backspace the value inside textBox1 then when that box is empty it still shows the calculate function using a zero in the calculation displayed inside the listbox as if the empty textbox is a zero if it's empty except when i backspace again it will go away. I was wondering why that is and what the logic is behind that. So to be clear
When i enter 12 the calculate functions show 12, and if i backspace it will be 1 and it will show the calculate function as 1 but if i backspace again to make it empty it will show the calculate function as 0 inside the listbox.Here is the screenshot
Thanks for your time and help.
You don't take the result of TryParse and whatever you have (or not have) in the textbox you run the calculate code. Check if the return of TryParse is false and exit the code
If TryParse is unable to parse the input string (like in case of an empty string) it sets the out variable to its default value (zero for double) and thus you have your code running against the zero multiplier.
This happens also if the user types a not numeric value like a letter.
private void Calculate()
{
if(!double.TryParse(textBox1.Text, out num))
return;
for (int a = 1; a <= 10; a++)
{
listBox1.Items.Add(a + " * " + num + "\n = " + a * num);
}
}
Let's say I have a string like this one, left part is a word, right part is a collection of indices (single or range) used to reference furigana (phonetics) for kanjis in my word:
string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす"
The pattern in detail:
word,<startIndex>(-<endIndex>):<furigana>
What would be the best way to achieve something like this (with a space in front of the kanji to mark which part is linked to the [furigana]):
子[こ]で 子[こ]にならぬ 時鳥[ほととぎす]
Edit: (thanks for your comments guys)
Here is what I wrote so far:
static void Main(string[] args)
{
string myString = "ABCDEF,1:test;3:test2";
//Split Kanjis / Indices
string[] tokens = myString.Split(',');
//Extract furigana indices
string[] indices = tokens[1].Split(';');
//Dictionnary to store furigana indices
Dictionary<string, string> furiganaIndices = new Dictionary<string, string>();
//Collect
foreach (string index in indices)
{
string[] splitIndex = index.Split(':');
furiganaIndices.Add(splitIndex[0], splitIndex[1]);
}
//Processing
string result = tokens[0] + ",";
for (int i = 0; i < tokens[0].Length; i++)
{
string currentIndex = i.ToString();
if (furiganaIndices.ContainsKey(currentIndex)) //add [furigana]
{
string currentFurigana = furiganaIndices[currentIndex].ToString();
result = result + " " + tokens[0].ElementAt(i) + string.Format("[{0}]", currentFurigana);
}
else //nothing to add
{
result = result + tokens[0].ElementAt(i);
}
}
File.AppendAllText(#"D:\test.txt", result + Environment.NewLine);
}
Result:
ABCDEF,A B[test]C D[test2]EF
I struggle to find a way to process ranged indices:
string myString = "ABCDEF,1:test;2-3:test2";
Result : ABCDEF,A B[test] CD[test2]EF
I don't have anything against manually manipulating strings per se. But given that you seem to have a regular pattern describing the inputs, it seems to me that a solution that uses regex would be more maintainable and readable. So with that in mind, here's an example program that takes that approach:
class Program
{
private const string _kinvalidFormatException = "Invalid format for edit specification";
private static readonly Regex
regex1 = new Regex(#"(?<word>[^,]+),(?<edit>(?:\d+)(?:-(?:\d+))?:(?:[^;]+);?)+", RegexOptions.Compiled),
regex2 = new Regex(#"(?<start>\d+)(?:-(?<end>\d+))?:(?<furigana>[^;]+);?", RegexOptions.Compiled);
static void Main(string[] args)
{
string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす";
string result = EditString(myString);
}
private static string EditString(string myString)
{
Match editsMatch = regex1.Match(myString);
if (!editsMatch.Success)
{
throw new ArgumentException(_kinvalidFormatException);
}
int ichCur = 0;
string input = editsMatch.Groups["word"].Value;
StringBuilder text = new StringBuilder();
foreach (Capture capture in editsMatch.Groups["edit"].Captures)
{
Match oneEditMatch = regex2.Match(capture.Value);
if (!oneEditMatch.Success)
{
throw new ArgumentException(_kinvalidFormatException);
}
int start, end;
if (!int.TryParse(oneEditMatch.Groups["start"].Value, out start))
{
throw new ArgumentException(_kinvalidFormatException);
}
Group endGroup = oneEditMatch.Groups["end"];
if (endGroup.Success)
{
if (!int.TryParse(endGroup.Value, out end))
{
throw new ArgumentException(_kinvalidFormatException);
}
}
else
{
end = start;
}
text.Append(input.Substring(ichCur, start - ichCur));
if (text.Length > 0)
{
text.Append(' ');
}
ichCur = end + 1;
text.Append(input.Substring(start, ichCur - start));
text.Append(string.Format("[{0}]", oneEditMatch.Groups["furigana"]));
}
if (ichCur < input.Length)
{
text.Append(input.Substring(ichCur));
}
return text.ToString();
}
}
Notes:
This implementation assumes that the edit specifications will be listed in order and won't overlap. It makes no attempt to validate that part of the input; depending on where you are getting your input from you may want to add that. If it's valid for the specifications to be listed out of order, you can also extend the above to first store the edits in a list and sort the list by the start index before actually editing the string. (In similar fashion to the way the other proposed answer works; though, why they are using a dictionary instead of a simple list to store the individual edits, I have no idea…that seems arbitrarily complicated to me.)
I included basic input validation, throwing exceptions where failures occur in the pattern matching. A more user-friendly implementation would add more specific information to each exception, describing what part of the input actually was invalid.
The Regex class actually has a Replace() method, which allows for complete customization. The above could have been implemented that way, using Replace() and a MatchEvaluator to provide the replacement text, instead of just appending text to a StringBuilder. Which way to do it is mostly a matter of preference, though the MatchEvaluator might be preferred if you have a need for more flexible implementation options (i.e. if the exact format of the result can vary).
If you do choose to use the other proposed answer, I strongly recommend you use StringBuilder instead of simply concatenating onto the results variable. For short strings it won't matter much, but you should get into the habit of always using StringBuilder when you have a loop that is incrementally adding onto a string value, because for long string the performance implications of using concatenation can be very negative.
This should do it (and even handle ranged indices), based on the formatting of the input string you have-
using System;
using System.Collections.Generic;
public class stringParser
{
private struct IndexElements
{
public int start;
public int end;
public string value;
}
public static void Main()
{
//input string
string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす";
int wordIndexSplit = myString.IndexOf(',');
string word = myString.Substring(0,wordIndexSplit);
string indices = myString.Substring(wordIndexSplit + 1);
string[] eachIndex = indices.Split(';');
Dictionary<int,IndexElements> index = new Dictionary<int,IndexElements>();
string[] elements;
IndexElements e;
int dash;
int n = 0;
int last = -1;
string results = "";
foreach (string s in eachIndex)
{
e = new IndexElements();
elements = s.Split(':');
if (elements[0].Contains("-"))
{
dash = elements[0].IndexOf('-');
e.start = int.Parse(elements[0].Substring(0,dash));
e.end = int.Parse(elements[0].Substring(dash + 1));
}
else
{
e.start = int.Parse(elements[0]);
e.end = e.start;
}
e.value = elements[1];
index.Add(n,e);
n++;
}
//this is the part that takes the "setup" from the parts above and forms the result string
//loop through each of the "indices" parsed above
for (int i = 0; i < index.Count; i++)
{
//if this is the first iteration through the loop, and the first "index" does not start
//at position 0, add the beginning characters before its start
if (last == -1 && index[i].start > 0)
{
results += word.Substring(0,index[i].start);
}
//if this is not the first iteration through the loop, and the previous iteration did
//not stop at the position directly before the start of the current iteration, add
//the intermediary chracters
else if (last != -1 && last + 1 != index[i].start)
{
results += word.Substring(last + 1,index[i].start - (last + 1));
}
//add the space before the "index" match, the actual match, and then the formatted "index"
results += " " + word.Substring(index[i].start,(index[i].end - index[i].start) + 1)
+ "[" + index[i].value + "]";
//remember the position of the ending for the next iteration
last = index[i].end;
}
//if the last "index" did not stop at the end of the input string, add the remaining characters
if (index[index.Keys.Count - 1].end + 1 < word.Length)
{
results += word.Substring(index[index.Keys.Count-1].end + 1);
}
//trimming spaces that may be left behind
results = results.Trim();
Console.WriteLine("INPUT - " + myString);
Console.WriteLine("OUTPUT - " + results);
Console.Read();
}
}
input - 子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす
output - 子[こ]で 子[こ]にならぬ 時鳥[ほととぎす]
Note that this should also work with characters the English alphabet if you wanted to use English instead-
input - iliketocodeverymuch,2:A;4-6:B;9-12:CDEFG
output - il i[A]k eto[B]co deve[CDEFG]rymuch
I have two buttons that contain their own functionality (which I have not included in the code snippet below as it is not relevant), but they also contain the same block of text (which is shown in the code snippet below). My question as I am a beginner in C#, is there a way where I can just write the code once and use the function shall I call to be placed in the buttons instead?
Code Snippet:
private void btnAlpha_Click(object sender, EventArgs e)
{
//Replace Non Alpha code would go here…
/*Count number of lines in processed text,
extra line is always counted so -1 brings it to correct number*/
int numLines = copyText.Split(“/n”).Length - 1;
//seperate certain characters in order to find words
char[] seperator = (" " + nl).ToCharArray();
//number of words, characters and include extra line breaks variable
int numberOfWords = copyText.Split(seperator, StringSplitOptions.RemoveEmptyEntries).Length;
int numberOfChar = copyText.Length - numLines;
//Unprocessed Summary
newSummary = nl + "Word Count: " + numberOfWords + nl + "Characters Count: " + numberOfChar;
}
private void btnReplace_Click(object sender, EventArgs e)
{
//Replace code would go here…
/*Count number of lines in processed text,
extra line is always counted so -1 brings it to correct number*/
int numLines = copyText.Split(“/n”).Length - 1;
//seperate certain characters in order to find words
char[] seperator = (" " + nl).ToCharArray();
//number of words, characters and include extra line breaks variable
int numberOfWords = copyText.Split(seperator, StringSplitOptions.RemoveEmptyEntries).Length;
int numberOfChar = copyText.Length - numLines;
//Unprocessed Summary
newSummary = nl + "Word Count: " + numberOfWords + nl + "Characters Count: " + numberOfChar;
}
In C# you can enclose reusable code in methods (as suggested in comments). If there are parts of the code that behave differently then again you can encapsulate them into a separate methods. Below the code that's repeated in each handler is in MyMethod. btnReplace specific code is in MyReplace and btnAlpha specific code is in MyAlpha:
private void btnReplace_Click(object sender, EventArgs e)
{
MyReplace();
MyMethod();
}
private void btnAlpha_Click(object sender, EventArgs e)
{
MyAlpha();
MyMethod();
}
private void MyReplace()
{
// Replace code
}
private void MyAlpha()
{
// Alfa code
}
private void MyMethod()
{
//Replace code would go here…
/*Count number of lines in processed text,
extra line is always counted so -1 brings it to correct number*/
int numLines = copyText.Split(“/n”).Length - 1;
//seperate certain characters in order to find words
char[] seperator = (" " + nl).ToCharArray();
//number of words, characters and include extra line breaks variable
int numberOfWords = copyText.Split(seperator, StringSplitOptions.RemoveEmptyEntries).Length;
int numberOfChar = copyText.Length - numLines;
//Unprocessed Summary
newSummary = nl + "Word Count: " + numberOfWords + nl + "Characters Count: " + numberOfChar;
}
If you need some sort of communication between the methods then one option would be to return a value from the first method and pass it into the second one.
Alternatively you can parameterize your main method (if true execute alfa part else execute replace part) and execute it with a parameter saying which part of the code to execute. But if there are many possible alternatives than probably producing separate method for each alternative makes more sense.
I have the following code in my TextBox leave event:
private void txtAmount_Leave(object sender, EventArgs e)
{
int x = Convert.ToInt32(txtAmount.Text);
double res = (double)x / 100;
txtAmount.Text = "$" + res.ToString();
}
But if move back to the previous control by hitting Shift+Tab and again moving back to the same textbox and then trying to move to other the form is getting closed automatically. Why does this happen?
The call to Convert.ToInt32() is probably throwing an exception, likely due to being unable to convert the string in your TextBox to an integer. Convert.ToInt32() can throw the following exceptions (descriptions from MSDN):
FormatException - value does not consist of an optional sign followed by a sequence of digits (0 through 9).
OverflowException - value represents a number that is less than Int32.MinValue or greater than Int32.MaxValue.
It's likely a FormatException, thrown when you leave the TextBox after the $ is prepended to your string, or after you enter any non-numeric characters (letters, etc). To fix this, you have a couple of options:
Add a try / catch block around your code to handle any exceptions.
Use Int32.TryParse() instead of Convert.ToInt32().
Add some code that will prevent non-numeric characters from being entered in your TextBox
Here's an improved version of your event handler:
private void txtAmount_Leave(object sender, EventArgs e)
{
string toParse = txtAmount.Text.TrimStart('$');
int parsed;
if (Int32.TryParse(toParse, out parsed))
{
double res = (double)parsed / 100;
txtAmount.Text = "$" + res.ToString();
}
}
The first time you leave this textbox, its contents will be changed to "$123" (for example). The second time you leave, trying to convert that to int will throw an exception.
You could use the overload of TryParse that takes a NumberStyle, something like this, assuming your goal is to just show a currency value with no decimal places.
double number;
if (double.TryParse(txtAmount.Text, NumberStyles.Currency, CultureInfo.CurrentUICulture, out number))
{
txtAmount.Text = number.ToString("C0");
}
else
{
MessageBox.Show("Could not convert.");
}
After reading #Donut's comment on his answer, I am not sure what your goal is. If you'd like to truncate the cents off but still show the ".00", you can do this:
txtAmount.Text = ((int)number).ToString("C");
Or do this, which will round:
txtAmount.Text = (Convert.ToInt32(number)).ToString("C");
If this does not help, please clarify and let us know what you are trying to accomplish.
Try this:
private void txtAmount_Leave(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(txtAmount.Text) && txtAmount.Text.StartsWith("$"))
txtAmount.Text = txtAmount.Text.Substring(1);
int x = Convert.ToInt32(txtAmount.Text);
double res = (double)x / 100;
txtAmount.Text = "$" + res.ToString();
}
Check the txtAmount.Text for the $ sign, before trying to convert it to an int. If the $ sign is present, strip it out, and convert the rest of the input to an int.
Also, you might want to use the Int32.TryParse method, as that will help you figuring out whether the entered text can be converted into an int or not.
You may want to change your code to remove the $ before working with the number:
private void txtAmount_Leave(object sender, EventArgs e)
{
int x = 0;
int.TryParse(txtAmount.Text.Replace("$", string.Empty), out x);
double res = (double)x / 100;
txtAmount.Text = "$" + res.ToString();
}
I got the solution
private void txtAmount_Leave(object sender, EventArgs e)
{
string strAmnt = string.Empty;
strAmnt = txtAmount.Text;
if (strAmnt.Contains(".") && !strAmnt.Contains("$"))
{
txtAmount.Text = "$" + strAmnt;
while (txtAmount.Text.Length - txtAmount.Text.IndexOf(".") <= 2)
{
txtAmount.Text += "0";
}
}
else
if (strAmnt.Contains("$") && !strAmnt.Contains("."))
{
Int64 amnt = 0;
strAmnt = strAmnt.Replace("$", "");
try
{
amnt = Convert.ToInt64(strAmnt);
double amt = (double)amnt / 100;
txtAmount.Text = "$" + amt.ToString();
}
catch (FormatException ie)
{
MessageBox.Show("Invalid Format");
}
}
else
if (!strAmnt.Contains(".") && !strAmnt.Contains("$"))
{
try
{
int x = Convert.ToInt32(txtAmount.Text);
double res = (double)x / 100;
txtAmount.Text = "$" + res.ToString();
while (txtAmount.Text.Length - txtAmount.Text.IndexOf(".") <= 2)
{
txtAmount.Text += "0";
}
}
catch (FormatException ie)
{
MessageBox.Show("InvalidFormat");
}
}
while (txtAmount.Text.Length - txtAmount.Text.IndexOf(".") <= 2)
{
txtAmount.Text += "0";
}
}