C# string toCharArray out of range exception - c#

I came across this issue while I was fixing someone else's code. apparently they were trying to control digits after the decimal point like this:
public static bool check_count(double d)
{
string str = d.ToString();
bool b = true;
if (str.IndexOf('.'))
{
char[] ch = str.ToCharArray(str.IndexOf('.'), str.Length - 1);
if (ch.Length > 5)
b = false;
}
return b;
}
I wasn't going to bother myself fixing that since I'm replacing it with regular expressions but it made me curious. the ToCharArray is throwing ArgumentOutOfRangeException when it shouldn't(?!)
let's say
string str = "20.222";
Console.WriteLine(str);
int index = str.IndexOf('.');
if (index > -1)
{
Console.WriteLine(index);
Console.WriteLine(str.Length-1);
char[] ch = str.ToCharArray(index, str.Length - 1);
}
output:
20.222
2
5
live demo [here]
so the string is 6 chars long and the start index is 2, what argument is out of what range?
I feel lost in this .. any ideas?
thanks

what argument is out of what range?
Well, I'd expect the exception to tell you that - but I'd also expect it to be the second argument. (EDIT: Looking at the exception you actually get, even from .NET, it's actually blaming the first argument. Admittedly it's the combination of the first and second arguments which is invalid, but it's more sensible to blame the second one in this case, as the first one is valid on its own.)
Look at the documentation - the second argument is the length, not the end index. So I suspect you want something like:
char[] ch = str.ToCharArray(index, str.Length - index);
Or to get just the digits after the .:
char[] ch = str.ToCharArray(index + 1, str.Length - index - 1);

Related

I want to use the Element at , length and substring method to remove something from string in c#

Problem statement:
Using just the ElementAt, Length, and Substring string methods and the + (concatenate)
operator, write a function that accepts a string s, a start position p, and a length l, and returns s with the characters starting in position p for a length of l removed. Don’t forget that strings start at position 0. Thus (“abcdefghijk”, 2, 4) returns “abghijk”. Don’t use any “remove” or similar built-in string gadget.
I tried to do this
static string rstring(string str, int p, int l)
{
string end= "";
for (int i=0 ; i<p; i++){
end+= str[i];
}
for (int i=p+l ; i<str.length i++){
end+= str[i];
}
return end;
}
I tried to do this but i couldn't figure out to use ElementAT and substring. Any help will be appricated.
You're using [] which is essentially the same thing as ElementAt, and if you look at your loops they're basically doing the same thing as Substring, albeit less efficiently because you're building up and throwing away a bunch of intermediate strings.
That said, I don't see why you'd use both -- you'd just use one or the other.
If you don't want to use Substring() or Remove() or any other string maninpulation I would use a simple loop (this doesn't include, but should include error handling).
for (int i=0; i < str.Length; i++)
{
if (i < p || i > l+1) end += str[i];
}
This basically just accepts a string, a start and an end and then returns a new string according to those parameters.
This is probably the easiest way to explain Substrings. They accept a start and end and then give you back a new string according to your start and end.
public string ReturnSubstring(string str, int start, int end)
{
return str.Substring(start, end);
}
var firstHalf = ReturnSubstring(myString, 0, 3);
var secondHalf = ReturnSubstring(myString, 6, myString.Length);
var newString = firstHalf + secondHalf;

Find if a string is empty

I have a homework to do and I have a string initialized like this:
string s= "abc,def,ghi,jkl,mno,,";
I have to check if near comma exists a char or there isn't anything. I have tried this code:
do{
if (s==','){
count++;
if (count==3)
if(s++!=',')
MessageBox.Show("Substring not empty");
else
MessageBox.Show("Substring empty");
}
}while(!String.IsNullOrEmpty(s));
but I have two errors:
Error 1 Operator '==' cannot be applied to operands of type 'string' and 'char'
Error 2 Operator '++' cannot be applied to operand of type 'string'
So, how can I verify if after the comma there is a char?
Well, this is homework, so something "advanced" like LINQ wouldn't be what I would turn in:
var somethingIsEmpty = str.Split(',').Any(e => e.Length==0);
Think about it a bit more, write some comments, write code underneath them:
//get the string
//split the string on commas, don't enable RemoveEmptyEntries
//use a loop to iterate through the whole splitted array
//if any element of the array has a zero length, show a message
When you're learning, this is a better way to code; write your algorithm in the language you think in, as comments.. Then translate the comments to code, end up with nicely commented code, that works. Failing to write comments means you run the risk of forgetting where you're going, what you're doing, what your algorithm is, and you revert to coding by trial and error without thinking about what you're actually doing
Having written the algorithm in comments, I can translate to code easily like this:
//get the string
string str = "a,b,c,,d";
//split the string on commas, don't enable RemoveEmptyEntries
string[] bits = string.Spilt(',');
//use a loop to iterate through the whole splitted array
for(int i = 0; i <= bits.Length; i++){
//if any element of the array has a zero length, show a message
if(bits[i].Length > 0)
MessageBox.Show("Element " + i + " has zero length");
}
This code contains three deliberate errors. I don't want to rob you of the learning opportunity you're supposed to be acquiring here; you need to think about this still- don't just hand this code in - work through it, think about it, fix the errors
Or from Dmitry's comment, investigate these:
yourstring.Contains(",,");
yourstring.StartsWith(",");
yourstring.EndsWith(",");
These return Booleans, if any of them are true, then your string is out of spec
'a' -- > is a char
"a" -- > is a string
This error messages very clear.
Error 1 Operator '==' cannot be applied to operands of type 'string' and 'char' -- > s is a string variable but ',' is a char value. You can't compare these two
Error 2 Operator '++' cannot be applied to operand of type 'string' --> where is the content variable ? and content is it numerical value ?
this code won't work.
Please try this
string s = "abc,def,ghi,jkl,mno,,";
string[] s2 = s.Split(',');
for (int i = 0; i < s2.Length; i++)
{
if (!string.IsNullOrEmpty(s2[i]))
Console.WriteLine("{0} Partition FULL",i.ToString());
else
Console.WriteLine("{0} Partition Empty", i.ToString());
}
Console.Read();
output
0 Partition FULL
1 Partition FULL
2 Partition FULL
3 Partition FULL
4 Partition FULL
5 Partition Empty
6 Partition Empty
First error: s is a string. When you do s==',', you are comparing a string to a char, because ',' is a char.
Second error: You cannot apply ++ operator to a string. You should access single characters of a string in the same way as you would access an item from an array (s[0] would get you the 1st character etc.).
Solution to both problems: initialize an int counter and use it to go through the string character by character by using i++ and s[i].
Here is a quick snippet:
int i = 0;
while(i < s.Length) {
// get the current character
char c = s[i];
if(c == ',') {
// current character is a comma
// check if the previous character was also a comma OR if the current position is at the start/end of the string
if(i == 0 || s[i - 1] == ',' || i == s.Length - 1) {
MessageBox.Show("Substring empty");
} else {
MessageBox.Show("Substring not empty");
}
}
// advance by one position
++i;
}

How do I not String.Remove anything?

I have a string that may or may not need truncating. I'm passing two non-negative integers as arguments to my program. The first one is supposed to tell the program how many characters need to be removed from the beginning of the string, and the second one tells it how many characters to remove from the end. Is there a way to do it so that zeroes work properly as input, the meaning of the code is self-evident and there are no silly conditional statements like if (removefirst != 0).
string.Remove(0, removefirst) needs the conditional statement because the first argument needs to be strictly less than the second one, says the exception message. Is there a way to do it more prettily?
Math + use Substring()?
var result = str.Substring(firstNumber, str.Length - (firstNumber + secondNumber));
DotNetFiddle Example
string yourstring = "asdf";
string result;
int firstNumber = 0;
int secondNumber = 0;
Console.WriteLine(yourstring);
result = yourstring.Substring(firstNumber, yourstring.Length - (firstNumber+secondNumber));
Console.WriteLine(result);
firstNumber = 1;
secondNumber = 1;
result = yourstring.Substring(firstNumber, yourstring.Length - (firstNumber+secondNumber));
Console.WriteLine(result);
Results
asdf
asdf
sd

Best way to remove characters from string in c# win. form

i have a string of length 98975333 and i need to remove first 5 letters in it. Can anyone suggest the best way to do this keeping performance in mind?
I tried
str.Substring(5,str.Length);
str.Remove(0,5);
which gives me result in 0.29 sec
but i want something even faster than the above.
Problem Using StringBuilder
-> i need to substring a part of the string and to do this i need to write
StringBuilder2.ToString().Substring(anyvaluehere)"
here the conversion of StringBuilder to string by ".ToString()" takes time and in this case i cant use StringBuilder
If you are working with long strings, always use StringBuilder. This class provides you fast adding and removing characters, faster than String.Concat or it's syntactic sugar "a" + "b". Moreover StringBuilder.ToString() method has special implementation for best performance as possible.
Sorry, c# strings are not arrays; they are immutable so extracting a (possibly very long) substring involves a copy.
However, most [string utilities] accept start and end indices, for instance IndexOf and CompareInfo.Compare all take a startIndexoverload.
Perhaps if you tell us what you want to do afterward we could suggest alternatives?
Update
Here are some ways you can write performant string parsing with the immutable strings in c#. Say for instance that you need to deserialize XML data inside the string, and need to skip the first N characters. You could do something like this:
public static object XmlDeserializeFromString<T>(this string objectData, int skip)
{
var serializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(objectData))
{
for (; skip > 0 && reader.Read() != -1; skip--)
;
return (T)serializer.Deserialize(reader);
}
}
As you can see from the source. StringReader.Read() does not make a copy of the unread portion of the string, it keeps an internal index to the remaining unread portion.
Or say you want to skip the first N characters of a string, then parse the string by splitting it at every "," character. You could write something like this:
public static IEnumerable<Pair<int>> WalkSplits(this string str, int startIndex, int count, params char[] separator)
{
if (string.IsNullOrEmpty(str))
yield break;
var length = str.Length;
int endIndex;
if (count < 0)
endIndex = length;
else
{
endIndex = startIndex + count;
if (endIndex > length)
endIndex = length;
}
while (true)
{
int nextIndex = str.IndexOfAny(separator, startIndex, endIndex - startIndex);
if (nextIndex == startIndex)
{
startIndex = nextIndex + 1;
}
else if (nextIndex == -1)
{
if (startIndex < endIndex)
yield return new Pair<int>(startIndex, endIndex - 1);
yield break;
}
else
{
yield return new Pair<int>(startIndex, nextIndex - 1);
startIndex = nextIndex + 1;
}
}
}
And then use the start and end indices of the Pair to further parse the string, or extract small substrings to feed to further parsing methods.
(Pair<T> is a small struct I created similar to KeyValuePair<TKey, TValue> but with identically typed first and second values. I can provide if needed.)
Using a StringBuilder to produce and manipulate the string will help you save on resources:
StringBuilder sb = new StringBuilder();
sb.Append("text"); //to add text in front
sb.Insert(50,"text"); // to insert text
sb.Remove(50,4); // to remove text
sb.ToString(); // to produce the string
If you have a fixed length of string that you wish to store elsewhere, you can make a char array and use StringBuilder's CopyTo() method:
e.g.
char[] firstfive = new char[5];
sb.CopyTo(0,firstfive,0,5);
Edit:
Actually, the OP figured this out himself, but I'm including it on the post for reference:
To get a portion of the StringBuilder as string:
sb.ToString(intStart,intLength)
Use String.Remove() i.e
String newStr = "";
newStr = str.Remove(0,5); //This will delete 5 characters starting from 0 index
Or
newStr = str.Remove(5); //Assumes the starting position as 0 and will ddelete 5 chars from that
Read more Here

Get the letters (ABCDE) between two letters (AE) using C#

I need to get the letters as an array on passing two letters using C#
For ex.: When i pass "AE", i need to get the {A,B,C,D,E} as an array. and passing "FJ" should return {F,G,H,I,J}.
The Enumerable class can create a range, which makes the looping simple:
public static char[] CharactersBetween(char start, char end) {
return Enumerable.Range(start, end - start + 1).Select(c => (char)c).ToArray();
}
Note: A char value converts implicitly into int, so there is no conversion needed in that direction. You only have to convert the integers back to char.
Edit:
If you want to send in the alphabet to use (to handle language differences), you can use Substring to get a part of that string:
public static char[] CharactersBetween(char start, char end, string alphabet) {
int idx = alphabet.IndexOf(start);
return alphabet.Substring(idx, alphabet.IndexOf(end) - idx + 1).ToCharArray();
}
Do you mean something like
char[] CharactersBetween(char start, char end)
{
List<char> result = new List<char>();
for (char i = start; i <= end; i++)
{
result.Add(i);
}
return result.ToArray();
}
This should work out well
string startandend = "AG";
string result= "";
for( char i = startandend[0]; i <= startandend[1]; i++){
result += i;
}
result will now contain ABCDEFG.
You should probably add some logic to check if startandend actually have a Length of 2 and so on, but this should be a good starting block for you.
If you want the char[] instead of the string representation, simply call result.ToCharArray() at the end.
Use a loop with integer conversion
with
System.Convert.ToInt32(Char);
and
System.Convert.ToChar(Int32);
see http://msdn.microsoft.com/en-us/library/system.convert_methods.aspx
Pretty simple if you use a fixed alphabet,
public static string ALPHABET = "ABCDEFGHIJKLMNOPWRSTUVWXYZ";
public static List<char> GetLetters(string firstLast)
{
List<char> letters = new List<char>();
int start = ALPHABET.IndexOf(firstLast[0]);
int end = ALPHABET.IndexOf(firstLast[1]);
for (int i = start; i <= end; i++)
{
letters.Add(ALPHABET[i]);
}
return letters;
}
Obviously add in your checks for various things, but it does the basic job.
You're going to have to reference whichever alphabet you want to use. English is easy enough as the letters happen to correspond to code-point order, French treats Œ and Æ as letters in their own right sometimes, and not others. Danish and Norwegian place "Æ, Ø, Å" after Z and Swedish does the same with "Å, Ä, Ö". Irish uses "ABCDEFGHILMNOPRSTU" as the alphabet, but does also use J, K, Q, V, W, X, Y & Z in loan words.
And those are relatively easy cases. So there's no one-size-fits-all.
The easiest way to pass an alphabet is to have a string that contains it. So, e.g. the Danish alphabet would have the string "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" while French could either include the ligatures or not as you wish (but do you need to deal with the possibility of receiving them while not using them?).
This done:
public static IEnumerable<char> AlphabetRange(string alphabet, string alphaRange)
{
if(alphaRange == null)
throw new ArgumentNullException();
if(alphaRange.Length < 2)
throw new ArgumentException();
int startIdx = alphabet.IndexOf(alphaRange[0]);
int endIdx = alphabet.IndexOf(alphaRange[1]) + 1;
if(startIdx == -1 || endIdx == 0)
throw new ArgumentException();
while(startIdx < endIdx)
yield return alphabet[startIdx++];
}

Categories

Resources