Stop a loop before a predictable error happens - c#

So I need to count lines in a textbox, to do this i use:
if (subject.Length <= 20)
{
bool moreLines = true;
int onLine = 2;
int count = 0;
while (moreLines)
{
textBody[count] = TextBox_Text.Text.Split('\n')[onLine];
Console.WriteLine("Line saved: " + textBody[count]);
onLine++;
count++;
try
{
if (TextBox_Text.Text.Split('\n')[onLine] == null)
{
}
}
catch (IndexOutOfRangeException)
{
moreLines = false;
}
}
return true;
}
I insert the split strings into textBody[] array but once I approach the last lines where there is no text I want the loop to stop. I tried to do an if statement which checks if the next line is null, and if yes stop the loop. However, I kept getting an IndexOutOfRangeException so I just put the whole thing in a try catch, but I feel like there would be an easier way to do this?

I think you might have over complicated things massively.
The String.Split method have multiple overloads, some of them takes as an argument a member of the StringSplitOptions enum - one of it's members is called None, and the other is called RemoveEmptyEntries - so as far as I understand, all you need is this:
var textBody = TextBox_Text.Text.Split(
new char[] {'\n'},
StringSplitOptions.RemoveEmptyEntries);

An easy way to do this would just to use the following:
TextBox_Text.Text.Split('\n').Length
The Length property returns the length of the array.

so I just used the LineCount property instead and done a compare to the onLine
if (TextBox_Text.LineCount >= onLine)
{
moreLines = false;
}

Related

Recommended way of checking if a certain string has a specified character more than once

Firstly I understand that there are several ways to do this and I do have some code which runs, but what I just wanted to find out was if anyone else has a recommended way to do this. Say I have a string which I already know that would have contain a specific character (a ‘,’ in this case). Now I just want to validate that this comma is used only once and not more. I know iterating through each character is an option but why go through all that work because I just want to make sure that this special character is not used more than once, I’m not exactly interested in the count per se. The best I could think was to use the split and here is some sample code that works. Just curious to find out if there is a better way to do this.
In summary,
I have a certain string in which I know has a special character (‘,’ in this case)
I want to validate that this special character has only been used once in this string
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Split(characterToBeEvaluated).Length - 1;
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
You can use string's IndexOf methods:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
string substringToFind = characterToBeEvaluated.ToString();
int firstIdx = myStringToBeTested.IndexOf(substringToFind, StringComparison.Ordinal);
bool foundOnce = firstIdx >= 0;
bool foundTwice = foundOnce && myStringToBeTested.IndexOf(substringToFind, firstIdx + 1, StringComparison.Ordinal) >= 0;
Try it online
You could use the LINQ Count() method:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Count(x => x == characterToBeEvaluated);
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
This is the most readable and simplest approach and is great if you need to know the exact count but for your specific case #ProgrammingLlama's answer is better in terms of efficiency.
Adding another answer using a custom method:
public static void Main()
{
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var characterAppearsOnlyOnce = DoesCharacterAppearOnlyOnce(characterToBeEvaluated, myStringToBeTested);
if (characterAppearsOnlyOnce)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
}
public static bool DoesCharacterAppearOnlyOnce(char characterToBeEvaluated, string stringToBeTested)
{
int count = 0;
for (int i = 0; i < stringToBeTested.Length && count < 2; ++i)
{
if (stringToBeTested[i] == characterToBeEvaluated)
{
++count;
}
}
return count == 1;
}
The custom method DoesCharacterAppearOnlyOnce() performs better than the method using IndexOf() for smaller strings - probably due to the overhead calling IndexOf. As the strings get larger the IndexOf method is better.

Where do i put the try-catch in my for-loop?

I'm now done with the basics of my code, and it works like it should. But now i want to add a try-catch exception so that if the user put is anything else than integers, it will throw an exception and say something like: Wrong input try again. Here is where i need it:
for (int i = 0; i < nummer.Length; i++)
{
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
int element = Convert.ToInt32(str);
nummer[i] = element;
}
The loop will loop 10 times and store the inputs in an array. When i try it either makes an exception but contiues the loop or breaks the loop and goes on to the next block of code..
I would favour the use of...
bool parsed = Int.TryParse(str, out myInt);
If (parsed)
{
// do something
}
IMHO, a try/catch block should only really be used when there is a possibility on an unhandled exception (e.g. something volatile such as filesystem interaction) that cannot be "predicted" so as to handle accordingly (e.g. log errors etc.) and then continue without crashing your program.
Always try and handle a "known" with the methods and functions available in the framework to do so.
What you're trying to do doesn't require a try-catch. You can use the TryParse method to check whether the desired input is a properly formed integer, and prompt the user to enter a different input.
for (int i = 0; i < nummer.Length; i++)
{
bool isAnInteger = false;
int element = 0;
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
// evaluates to true if str can be parsed as an int, false otherwise
// and outputs the parsed int to element
isAnInteger = int.TryParse(str, out element);
while (!isAnInteger)
{
Console.Write("Wrong input, try again. ");
str = Console.ReadLine();
isAnInteger = int.TryParse(str, out element);
}
nummer[i] = element;
}
Use the int.TryParse method.
This code reads the trimmed input string from the user and tries to convert it to an integer. If the conversion is successful, it creates an integer variable called "result" which you can then use in the IF block. If the conversion fails, you can write the code for what you want to happen in the ELSE block. If you need a total of 10 integers in the list, I would drop the FOR loop in favor of a DO WHILE loop that checks for how many integers were successfully converted and added to the list. It will keep requesting input until the list is filled with 10 integers.
List<int> elements = new List<int>();
do
{
Console.WriteLine("Please enter an integer.");
if (int.TryParse(Console.ReadLine().Trim(), out int result))
{
Console.WriteLine($"You entered the integer {result}");
elements.Add(result);
}
else
{
Console.WriteLine("You must enter an integer. Please try again.");
}
} while (elements.Count < 10);
If you want to keep your code with the try catch loop here it is:
for (int i = 0; i < nummer.Length; i++)
{
try {
Console.Write("Nummer " + talnr + ": ");
talnr++;
string str = Console.ReadLine();
int element = Convert.ToInt32(str);
nummer[i] = element;
}
catch
{
MessageBox.Show("Error, numbers only");
goto breakloop;
}
}
breakloop:;
The goto statement ends the loop if an error occured
It's a good idea to not throw exceptions at all if you can help it. In this case, you can use int.TryParse() instead. This block of code can replace your one int element... line:
int element;
if (!int.TryParse(str, out element)) {
Console.WriteLine("Bad!!");
i--;
continue;
}
The i-- is to make sure that i has the same value on the next interaction of the loop. Doing that will make sure you still get 10 valid inputs before you finish the loop. (Many will say this is a really bad thing to do, but the reason for that is readability - if you have a large for loop and decrement the value somewhere in the middle, it makes it difficult for the next guy looking at your code to understand exactly what's going on. But this is a short loop, so it's pretty obvious. Just be aware of this.)
The continue keyword skips the rest of that iteration of the loop and moves on to the next (so you don't add the bad value to your array).

I need to compare 2 strings using a For loop in c#

I need to compare 2 strings using a For without using String.compare. (It's a homework ... I started programming C# 2 weeks ago)
I just can't figure out how to use the for loop to answer the question. I don't know what to put in for(). I tried for( string text1 = "something",) but I can't figure out what toput after the, in the for loop.
Since this is a homework question, I would recommend stop reading the answer as soon as you think you have enough information to solve it on your own before getting to the solution at the end.
Let's assume a simple method signature, first:
public static bool AreStringEqual(string str1, string str2)
{
}
And our goal is to implement (write the code for) this method. We'll assume our goal is Return true if the strings are equal, and return false if they are not. We won't do anything fancy like make it case insensitive.
We can do some basic checks on our strings, first. If they are of different length, then we can immediately assume the strings are different, and return false:
if (str1.Length != str2.Length)
{
return false;
}
This block checks the length, and if they differ, then false is immediately returned and the rest of the method doesn't get executed.
At this point we can guarantee the strings are the same length, so we can loop over the strings and compare them character by character using a for loop.
for(int counter = 0; counter < str1.Length; counter++)
{
}
This is a pretty standard for-loop that just counts a number from zero to one less than the length of the string. It doesn't matter if we use str1 or str2 for the upper bound of the loop since we already know they are the same length.
To get the character in a string, we can use the Indexer Syntax to get the character at a give position. The numbers start at zero in C# and .NET.
str1[0] gets the first character, str1[1] gets the second, etc.
We can then plug the variable in the for loop into the indexer for str1 and str2, then compare the characters. If they are not equal, then return false.
for(int counter = 0; counter < str1.Length; counter++)
{
if (str1[counter] != str2[counter])
{
return false;
}
}
And finally, if the code gets through the for loop without returning false, then return true at the end. Putting it all together, it looks like this:
public static bool AreStringEqual(string str1, string str2)
{
if (str1.Length != str2.Length)
{
return false;
}
for(int counter = 0; counter < str1.Length; counter++)
{
if (str1[counter] != str2[counter])
{
return false;
}
}
return true;
}

How to find a pair of chars within a string in c# netMF?

This has probably (somewhere) been asked before, but can't find any documentation on it (i have looked!).
Say I had declared a string like:
String Test = "abcdefg";
How would i go about searching the string to see if I could see "cd" anywhere in the string by searching through the string in pairs, like:
{ab}{bc}{cd}{de}{ef}{fg}
That is, if I split each of the values up, and searched for a pair of chars next to each other? Is there a built in function for this?
I have thought about using a char array for this, but it seems to (logically) be very 'heavy'/'slow'. Would there be a better solution to search this string?
EDIT 1
Once I see this "cd", I would then need to doSomething() at that position (which I have already implemented by using the substring method.
Try this.
String.IndexOf(...) != -1
For more infö, read here.
Similar to the answer from Neo, but in a loop to get all instances within the string:
string Test = "abcdefgcd";
int index = Test.IndexOf("cd");
while (index > -1)
{
//DoSomething();
index = Test.IndexOf("cd", ++index);
}
The first IndexOf checks for the existence of what you want, whilst the second IndexOf (in the loop) checks for a match after the last index.
In the above we find two matches and then the loop ends.
There is no build in function that will do that.
having a for loop should do what you want.
something like that:
string str = string.empty;
for (i=0;i<ch.length;i++) {
if (i != ch.length) {
str += ch[i] + ch[i+1];
}
}
also you can use regex however that wont be fast either.
In order to optimize this on a large scale you can implement byte shifting.
The ASCII code of your string characters is your friend in this case, full working example below:
var yourString = "abcdefg";
var x = '\0';
for (var i = 0; i < yourString.Length; i++)
{
//check whether i+1 index is not out of range
if (i + 1 != yourString.Length)
{
var test = yourString[i + 1];
x = yourString[i];
if(x.ToString() + test.ToString() == "cd")
{
Console.Write("Found at position " + i)
}
}
}

Splitting up a text file is incredibly slow

I have a database in a text file, split up by certain words (NUM/OPP/TUM/YUR/etc) to know where each piece of data should go. The issue is that running this is very slow, it would take about an hour to get through all three thousand things in the .txt file, most likely due to the .Split() (I think).
Is there a faster way to do this?
wholepage = streamReader.ReadToEnd();
while (true)
{
tempword = wholepage.Split()[tempnum];
tempnum++;
if (lastword == "NUM")
{
things[number_of_things].num = tempword;
number_of_things++;
slist.Add(new string[] { tempword });
listBox5.Items.Add(tempword);
}
lastword = tempword;
}
Thanks in advance.
Edit: Thanks for the help guys...and yes it was infinite loop, which didn't matter at the time since it would never make it through the loop once (unless you waited an hour).
Yes, split your input only once, on once every time loop is executed:
wholepage = streamReader.ReadToEnd();
var split = wholepage.Split();
while (true)
{
tempword = split[tempnum];
// (...)
}
And btw. you doesn't stop your loop so it potentially never ends (well, actually it does, when index is greater than number of items in array and exception is thrown). You should probably use foreach instead of while:
wholepage = streamReader.ReadToEnd();
var split = wholepage.Split();
foreach(var tempword in split)
{
if(lastword == "NUM")
{
things[number_of_things].num = tempword;
number_of_things++;
slist.Add(new string[] { tempword });
listBox5.Items.Add(tempword);
}
lastword = tempword;
}
Don't repeatedly Split!
Take this outside the loop...
myPage = wholepage.Split();
Then in your loop:
tempword=myPage[tempnum]
Also, instead of while(true), which will just keep looping, use a for loop
where myPage.length < tempnum

Categories

Resources