Logical error in simple acronym generator - c#

I have some kind of logical error in my program. Whenever I enter a phrase with 1 letter I get a ArgumentOutOfRange Exception, and whenever I enter a multiple letter word the textbox clears, displays "Apple" (the first value in my array) and does nothing else. Can anybody see the logical error in this?
string[] d = { "Apple", "Bass", "Cat", "Dog", "Ear", "Flamingo", "Gear", "Hat", "Infidel", "Jackrabbit", "Kangaroo", "Lathargic", "Monkey", "Nude", "Ozzymandis", "Python", "Queen", "Rat", "Sarcastic", "Tungston", "Urine", "Virginia", "Wool", "Xylophone", "Yo-yo", "Zebra", " " };
string var;
int len = 0;
private void button1_Click(object sender, EventArgs e)
{
var = textBox2.Text;
textBox1.Text = "";
for (int y = 0; y < var.Length; y++)
{
for (int x = 0; x < d.Length; x++)
{
if (d[x].ToUpper().Substring(0, 0) == var.ToUpper().Substring(len, len))
{
len = len + 1;
textBox1.Text = textBox1.Text + "\n" + d[x];
}
}
}
}

Substring(0, 0) is really pointless. This will always be an empty string.
Substring(len, len) also is a bad idea, because it will return a string of length len starting at index len. This is where you get your exception.
I assume, what you really want is the second parameter to be 1 in both cases. And that can be further simplified to an access via index:
d[x].ToUpper()[0] == var.ToUpper()[len]

You can do the same quite easily using LINQ:
private void button1_Click(object sender, EventArgs e)
{
var dict = d.ToDictionary(x => x.First(), x => x);
textBox1.Text = string.Join(Environment.NewLine, textBox2.Text.Select(x => dict[char.ToUpper(x)]));
}
To do it without LINQ I would suggest following:
for (int y = 0; y < input.Length; y++)
{
for (int x = 0; x < d.Length; x++)
{
if (char.ToUpper(d[x][0]) == char.ToUpper(input[y]))
{
result = result + "\n" + d[x];
}
}
}
Changes are:
you don't need len variable. Use y instead.
you don't need whole string uppercased. Use char.ToUpper static method instead.
you don't need string.Substring method. Use indexers instead.

This line explains the behavior.
if (d[x].ToUpper().Substring(0, 0) == var.ToUpper().Substring(len, len))
Second parameter of substring is string length. So on the left you always have an empty string. On the right you also have empty string when len==0 (that's why your code always picks Apple).
After that you change len, and repeat the loop. Then expression on the right is var.Substring(1,1) which gives you the error if your string is 1 character long. Because this reads - 1 symbol starting with 1 (which is second character of the string)
Apart from that, the purpose of the code is complete mystery, so there are definitely other errors.

Related

Splitting the letters based on position of letter

I am trying to spilt a string word into two strings based on the letter position. The two strings are even and odd. I manage to read the string and used a for loop but the conditional operator is not working and give me the error below. What did I do wrong?
Example: The string word is pole
Even position string - oe
Odd position string - pl
Error
Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
string word = Console.ReadLine();
for(int i = 0; i < word.Length; i++)
{
string even = "";
string odd = "";
((i % 2 == 0) ? even += word[i]: odd += word[i]);
}
You could use the discard operator as the following.
string word = Console.ReadLine();
string even = "";
string odd = "";
for(int i = 0; i < word.Length; i++)
{
var _ = ((i % 2 == 0) ? even += word[i]: odd += word[i]);
}
Couple of points to note here.
You need to declare the odd,even variables outside the loop, otherwise it would be recreated for each iteration of loop
Remember the string is immutable.You could also consider the StringBuilder class.
I am not that familiar with the ? operator, however, in my research, it appears it wants something like below…
((i % 2 == 0) ? ref even : ref odd) += word[i];
Unfortunately, even with this change, the even and odd variables are getting “reset” to empty with each iteration of the for loop with…
string even = "";
string odd = "";
If the goal is to concatenate the values, you do NOT want to create new even and odd variables with each iteration. So you should move those declarations “outside” the for loop. Something like…
string word = Console.ReadLine();
string even = "";
string odd = "";
for (int i = 0; i < word.Length; i++) {
((i % 2 == 0) ? ref even : ref odd) += word[i];
}
You use conditional operator to assign values inside of it. It is not allowed.
The correct for-loop is:
for (int i = 0; i < word.Length; i++)
{
if (i % 2 == 0)
{
even += word[i];
}
else
{
odd += word[i];
};
}
You can also use LINQ to get the expected result:
string word = Console.ReadLine();
string even = string.Concat(word.Where((c,i) => i % 2 == 0));
string odd = string.Concat(word.Where((c,i) => i % 2 == 1));
Online demo: https://dotnetfiddle.net/ePWHnp

Why can debugger give another result than common run in C#?

I'm working on this task on CodeWars: https://www.codewars.com/kata/5667e8f4e3f572a8f2000039/train/csharp.
My code should turn string like this "ZpglnRxqenU" in something like this "Z-Pp-Ggg-Llll-Nnnnn-Rrrrrr-Xxxxxxx-Qqqqqqqq-Eeeeeeeee-Nnnnnnnnnn-Uuuuuuuuuuu".
But I'm getting an error: "Z-Pp-Ggg-Lll-...". It returns three letters "l" instead of four letters.
I tried this code on my PC and the result is the same. But when I use debugger it shows the correct result. How can that be?
Here's my code:
using System;
public class Accumul
{
public static String Accum(string s)
{
string result = "";
for (int i = 0; i < s.Length; i++)
{
result += char.ToUpper(s[i]);
for (int j = 0; j < i; j++)
{
result += char.ToLower(s[i]);
}
result += "-";
}
result = result.Remove(s.Length - 1, 1);
return result;
}
}
You are probably checking result when you debug.
But the error is only at the end result = result.Remove(s.Length - 1, 1);
s.Length - 1 removes the 10th character, you need result.Length -1.

Why the value of "count" is showig 1 instead of 2?

In my below code I was trying to find the number of words that are in between "-", so I used string.Equals(), but it is not working. And just incrementing the value of "count" in the print section.
static void Main()
{
int count=0, i;
string inputString = "Anupam-Datta";
Console.WriteLine(inputString.Length);
for(i = 0; i < inputString.Length; i++)
{
if(inputString[i].Equals("-"))
count++;
}
Console.WriteLine("Number of words: {0}", ++count);
}
In order to check a single character - that is what inputString[i] actually returns - you have to compare it to another char, not to a string.
Ths use the follwoing instead:
Console.WriteLine(inputString.Length);
for(i=0; i<inputString.Length; i++){
if(inputString[i] == '-')
count++;
}
Console.WriteLine("Number of words: {0}", count++);
Alternativly this smart one-liner:
var count = inputString.Count(x => x == '-') + 1;
If you need the number of words, which are separated by the char "-", try this:
public static void Main()
{
string s = "Anupam-Datta";
int count = s.Split('-').Count();
Console.WriteLine($"Numer of words: {count}.");
}

Replace each character of string with new character string

The c# program I'm developing checks the first character of user input and if it starts with . (dot) I want to replace each character of user input with pacified character string while the user is writing, but I'm getting the error
Index out of bounds exception
My code:
if (textBox1.Text.StartWith(".")) {
string MyText = "Hello World";
int x = 0;
string NewText;
while (x <= MyText.Length) {
NewText = textBox1.Text.Replace(textBox1.Text[x], MyText[x]);
TextBox1.Text = NewText;
x++;
}
}
You're overrunning the bounds of the string, replace:
while (x <= MyText.Length) {
with
while (x < MyText.Length) {
while(x < MyText.Length)
or
while(x <= MyText.Length - 1)
If array has length = x, its last index is x-1, because array starts from 0 index
If I understand you right (there're no samples in question), I suggest using Linq which is straitforward; try using modular arimethics - index % MyText.Length to avoid index problems
string source = ".My Secret Message for Test";
string MyText = "Hello World";
// If user input starts with dot
if (source.StartsWith("."))
source = string.Concat(source
.Select((c, index) => MyText[index % MyText.Length]));
TextBox1.Text = source;
Outcome:
Hello WorldHello WorldHello
First of all as #Daniell89 said:
use
while(x < MyText.Length)
Secondly:
You use x as an index not only for MyText but for textBox1.Text too. So you need to check that it is long enough.
you can do something like this:
while (x < Math.Min(MyText.Length, textBox1.Text.Length)
{
NewText = textBox1.Text.Replace(textBox1.Text[x], MyText[x]);
TextBox1.Text = NewText;
x++;
}
But I think it would be better to use for statement here.

How to decrement the index of a line in an array of strings?

I am making a code that decrements the line index in an array of strings. My array is like this:
1.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
2.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
and so on. The lengths of the lines are not the same.
I want the text to be like this:
0.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
1.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
I have made this code:
int s = 0;
while(s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0,1));
lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString());
Console.WriteLine(lineCounter[s]);
}
else
Console.WriteLine(lineCounter[s]);
s++;
The "if" is executed only when the line contains the number and when the line is not a new line. The else is executed to write the other lines in the array.(I'm using console.writeLine to see the results. I know I have to change that part)
When I execute this code, I get the following exception in the "if" statement:
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
Additional information: Index and length must refer to a location within the string.
To me this means that "if" is executed even when the new line between the last line of the first text block and the first line of the second text block is encountered. I can't explain why. Help please!
Declaring dotIndex with combination of string.Remove() and string.Insert() may do the trick.
string[] lineCounter = new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n"
};
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) //must be at least in the position of 2 or above
continue;
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
}
I prefer to use for-loop to make the loop more definite, but you could change that to while/do.
This works fine in my PC. Output:
Edit:
All the results should be in the lineCounter. If you want to see them along the function, you could do:
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) { //must be at least in the position of 2 or above
//Print here
continue;
}
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
//Print here also
}
you probably want this:
string[] lineCounter=new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n"
};
int v = 0;
int s = 0;
while (s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0, 1));
Console.WriteLine(lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString()));
}
else
Console.WriteLine(lineCounter[s]);
s++;
}
I believe you may be having issues with empty lines on the string array.
Maybe something like this works for you.
IEnumerable<string> ShiftIndexes(IEnumerable<string> lines) {
foreach (string line in lines) {
if (!string.IsNullOrEmpty(line) && char.IsDigit(line, 0)) {
int dotPos = line.IndexOf('.');
int index = int.Parse(line.SubString(0, dotPos));
yield return (index - 1).ToString() + line.SubString(dotPos);
}
else
yield return line;
}
}
And then use it like this:
string[] shiftedLines = ShiftIndexes(originalLines).ToArray();

Categories