ArgumentOutOfRangeException when using lastIndexOf() - c#

I'm really stumped as to why I'm getting an exception. Here is a SSCCE I put together to demonstrate:
static void Main(string[] args)
{
string tmp =
"Child of: View Available Networks (197314), Title: N/A (66244)";
Console.WriteLine(tmp);
int one = tmp.LastIndexOf('('), two = tmp.LastIndexOf(')');
//my own error checking
Console.WriteLine(tmp.Length);//returns 63
Console.WriteLine(one < 0);//returns false
Console.WriteLine(two > tmp.Length);//returns false
Console.WriteLine(one);//returns 56
Console.WriteLine(two);//returns 62
/*
* error occurs here.
* ArgumentOutOfRangeException Index and length must refer to
* a location within the string.
* Parameter name: length
*/
string intptr = tmp.Substring(one, two);
Console.WriteLine(intptr);
}
I can't see what I am doing wrong (though coming from a Java background it might be trivial), hopefully someone else can.

substrings 2nd parameter is the length of the string you want to extract and not the position in the string.
You could do
string intptr = tmp.Substring(one + 1, two - one - 1);

Your code
tmp.Substring(one, two);
should be
tmp.Substring(one, (two-one+1));
second parameter is the length of the substring you wantwhile i think you're using it like it were the ending index.
And because i love LINQ, it might also be done like this:
string.Join(string.Empty, s.Skip(5).Take(7 - 5 + 1)); //build a string from IEnumerable<char>

string.Substring(startIndex, count)
you wrote startIndex and finishIndex, it's wrong

Related

Math.Ceiling giving "Call is ambiguous" error when using String.Length

Good day all.
I am getting back into C# after a few years, and am little stuck on an error I'm receiving. I wrote a practice program to determine whether a word is a palindrome (same backwards and forwards). I am however getting an error that confuses me.
I try to call Math.Ceiling(word.Length / 2) to get the middle of a word, but it gives me the following error:
"The call is ambiguous between the following methods or properties:'Math.Ceiling(decimal) and Math.Ceiling(double)"
Although I get that this is the compiler worrying about identifying the correct overloaded method, but am unsure how to indicate which I am using. I also don't get why should this matter?
Here is my full program:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string word = "Deleveled";
word = word.ToUpper();
bool isPalindrome = true;
for (var i = 0; i <= Math.Ceiling(word.Length / 2); i++)
{
char tmp = word[word.Length - i - 1];
if (Char.ToUpper(word[i]) != Char.ToUpper(tmp))
{
isPalindrome = false;
break;
}
}
Console.WriteLine(isPalindrome);
Console.ReadLine();
}
}
}
I would greatly appreciate it f anyone could help me understand what the issue is here?
My thanks in advance
Integer division always results in an integer; so: word.Length / 2 returns int (it rounds down).
When you call Math.Ceiling on this, you are passing an integer, but there is not Math.Ceiling(int). It has two choices: Math.Ceiling(double) and Math.Ceiling(decimal), but: it could use either, and neither of those is better from the compiler's perspective.
Frankly, it might be simpler to use the general purpose "page count" formula:
int pages = (items + pageSize - 1) / pageSize;
which in this case becomes simply:
int upperLimit = (word.Length + 1) / 2;
(note that the general purpose page count formula can also be written int pages = ((items - 1) / pageSize) + 1;, although in this case it would be harder to substitute your fixed page size)
It is because Math.Ceiling() only accepts a double datatype parameter and most of the time we unknowingly pass int or float, so just type casting those values to double will solve the issue
typecasting the "int" value to "double" value would look like this :::
Math.Ceiling((double) (15)); //here 15 is an int value which will be typecasted to double

OutOfRangeException in StringBuilder.Remove()

I have a string which contains a lot of useless information after the first char: space. So I built a StringBuilder to remove unnecesary characters after the first space.
public static string Remove(string text)
{
int index1 = text.IndexOf(' ');
int index2 = text.Lenght;
StringBuilder sv = new StringBuilder(text.Lenght);
sv.Append(text);
sv.Remove(index1, index2);
string text2 = sv.ToString();
return text2;
}
Can somebody explain why this throws me an error? Thank you!
The reason for this exception is that you misunderstood the purpose of the second parameter: rather than specifying the ending index, it specifies the length of the segment to be removed.
Since your code is passing the length of the entire text string, the only valid input for the first parameter would be zero. To pass a proper value, subtract the first index from the second index, and add 1 to the result.
Note: It looks like you are removing everything from the string starting at the first space ' '. A simpler way of doing it would be with substring:
int index = text.IndexOf(' ');
return index >= 0 ? text.Substring(0, index) : text;
The documentation for Remove says it all - only one exception is raised for that method
ArgumentOutOfRangeException: If startIndex or length is less than zero, or startIndex + length is greater than the length of this instance.
So one of two things is going on
Your string does not contain a space (startIndex will be less than zero)
The startIndex+length is greater than the total length of the string.
Crucially, with the code you've posted 1. above could sometimes be true, and 2. will always be true! You should have done index2-index1 for the second parameter.

Multiply two arrays gives wrong result

I just have two simple arrays of double Values! I get the input from the user and the size of the arrays are equal (always). The thing is, I am multiplying them using:
int sizeof_secondarray = entArray.Length;
for (int i = 0; i <sizeof_secondarray; i++)
{
prod = freqArray[i] * entArray[i];
Console.WriteLine("PROD= " + prod.ToString("#.##"));
}
So, the user gives input for array (freqArray) 50 & 60
and for the array (entArray) 0.52 & 0.47
but the product it gives me is:
PROD=
PROD= 23.5
PROD=
I am totally new to c# and missing something badly here, can somebody help me please?
Based on your partial code and your inputs, I see three points here:
1- The length of your arrays are 3, since you have three outputs, while you mentioned providing only 2 numbers per array. Thus there are some errors when you fill the arrays.
2- Since prod.ToString("#.##") returned empty strings in first and third printout, it means that entArray[0]*freqArray[0] and entArray[2]*freqArray[2] are zeros (x.ToString("#.##") returns empty string when x=0).
3- Based on 1 and 2, my blind guess is that your arrays are filled like this: {0,50,60} and
{0.52,0.47,0}, leading to the shown result.
Conclusion: Fix the section of the code where you get inputs from the user. There is absolutely no problem with the code section you provided here.
Change the for loop to below and try
for (int i = 0;i <sizeof_secondarray - 1; i++)
Update :
Sorry i overlooked into the question and gave wrong suggestion. I have tested the scenario using below code and it gave me correct answer. Are you declaring the variables, specifically "prod" in the below manner? Below code may give some hint to you.
static void Main(string[] args)
{
double[] entArray = new double[] { 0.52, 0.47 };
int sizeof_secondarray = entArray.Length;
double prod;
double[] freqArray = new double[] { 50, 40};
for (int i = 0; i < sizeof_secondarray; i++)
{
prod = freqArray[i] * entArray[i];
Console.WriteLine("PROD= " + prod.ToString("#.##"));
}
Console.Read();
}
Answer :
PROD= 26
PROD= 18.8

C# take a substring of a string

I am taking a line from a file only if that file doen't have a specific pattern.. and i want to take from that line the last 3 chars... my code is:
while (!line.Contains(pattern))
{
String num = line.Substring((line.Length - 3), (line.Length - 2));
System.Console.WriteLine(num);
}
but i get an error..
Index and length must refer to a location within the string.
Parameter name: length
why i get that? i am starting the new string 3 chars before the end of the line and i stop 2 chars before.. :\
Substring takes an offset and then a number of characters to return:
http://msdn.microsoft.com/en-us/library/aa904308%28v=VS.71%29.aspx
So:
String num = line.Substring((line.Length - 3), 3);
This of course assumes that line.Length > 3. You could check with:
String num = (line.Length < 3) ? line : line.Substring((line.Length - 3), 3);
Second argument of Substring is how many chars it have to take starting from first argument. It should just look like that:
String num = line.Substring(line.Length - 3, 3);
This is dangerous. What if the length of the line is < 3? You should probably check this otherwise you will get an exception.
In addition you should use the substring method as depicted here :
String num = line.Substring((line.Length - 3), 3);
The problem is that you try to get more characters then your array have.
Extensions are best for problems like this one ;) Mine have some dirty name but everyone know what it would do - this is exception safe substring:
public static string SubstringNoLongerThenSource(this string source, int startIndex, int maxLength)
{
return source.Substring(startIndex, Math.Min(source.Length - startIndex, maxLength));
}
So in your exact problem it should be like that:
String num = line.SubstringNoLongerThenSource((line.Length - 3), 3);
System.Console.WriteLine(num);
So num will have max 3 letters if the string you provide to function have enough letters :)
String num = line.Substring(line.Length - 3)
This is happening because the last parameter of Substring() should be the length of the string to extract.
In your case it should be 3
, and not line.Length - 2
The first parameter should also be:
line.Length - 3

Neat solution to a counting within a string

I am trying to solve the following problem but cannot find an elegant solution. Any ideas?
Thanks.
Input - a variable length string of numbers, e.g.,
string str = "5557476374202110373551116201";
Task - Check (from left to right) that each number (ignoring the repetitions) does not appear in the following 2 indexes. Using eg. above, First number = 5. Ignoring reps we see that last index of 5 in the group is 2. So we check next 2 indexes, i.e. 3 and 4 should not have 5. If it does we count it as error. Goal is to count such errors in the string.
In the above string errors are at indexes, 3,10 and 16.
in addition to the other excellent solutions you can use a simple regexp:
foreach (Match m in Regexp.Matches(str, #"(\d)(?!\1)(?=\d\1)"))
Console.WriteLine("Error: " + m.Index);
returns 3,10,16. this would match adjacent errors using lookahead with a backreference. handles repetitions. .net should support that. if not, you can use a non-backreference version:
(?<=0[^0])0|(?<=1[^1])1|(?<=2[^2])2|(?<=3[^3])3|(?<=4[^4])4|(?<=5[^5])5|(?<=6[^6])6|(?<=7[^7])7|(?<=8[^8])8|(?<=9[^9])9
A simple indexed for loop with a couple of look ahead if checks would work. You can treat a string as a char[] or as an IEnumerable - either way you can use that to loop over all of the characters and perform a lookahead check to see if the following one or two characters is a duplicate.
Sorry, not a C# man, but here's a simple solution in Ruby:
a="5557476374202110373551116201"
0.upto(a.length) do |i|
puts "error at #{i}" if a[i]!=a[i+1] && a[i]==a[i+2]
end
Output:
error at 3
error at 10
error at 16
Here's something I threw together in C# that worked with the example input from the question. I haven't checked it that thoroughly, though...
public static IEnumerable<int> GetErrorIndices(string text) {
if (string.IsNullOrEmpty(text))
yield break;
int i = 0;
while (i < text.Length) {
char c = text[i];
// get the index of the next character that isn't a repetition
int nextIndex = i + 1;
while (nextIndex < text.Length && text[nextIndex] == c)
nextIndex++;
// if we've reached the end of the string, there's no error
if (nextIndex + 1 >= text.Length)
break;
// we actually only care about text[nextIndex + 1],
// NOT text[nextIndex] ... why? because text[nextIndex]
// CAN'T be a repetition (we already skipped to the first
// non-repetition)
if (text[nextIndex + 1] == c)
yield return i;
i = nextIndex;
}
yield break;
}

Categories