C# take a substring of a string - c#

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

Related

How do i find the last letter inside a string, and get its index?

Let's say I have a string called test,
string test = "hello my dear world"
and I want to get the last letter's index, (which is 19) .
How do I get that index, and insert it into an int/string?
This is extremely simple.
string test = "Hello World";
char theLastCharacterOfTest = test[test.Length - 1]; // 'd'
int theIndexOfTheLastCharacter = test.Length - 1; // 10
Want an explanation? Here it is!
Let's start with getting the index of the last character. Since C# uses a 0-based index system (i.e. the first index is 0), the last index is the length of the string - 1.
The last character is just the character at the last index, right? And the indexer of string returns the character at the index passed in. If we combine these two, we get test[test.Length - 1].
I don't think you are very familiar with indexers, so here's a link:
https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
I'm not sure whether you're looking for the index or position of the last character (you said the index is 19, but that's the position...the index is 18). Here's both:
string test = "hello my dear world";
// The length of the text gives the position of the last char
int position = test.Length;
// C# has a 0-based index. You need the string length -1 to get the last char's position
int index = test.Length - 1;
Here's a working example.
int index = test.Length;
char LastLetter = test[index - 1];
please search , before posting your question.
string test = "hello my dear world";
int index = test.FindIndex(x => x.StartsWith("d"));
OR
int index = test.Length - 1;

Bifurcate a string, removing the middle of the string instead of end

I want something similar to this question I found lead me to this answer on another question where I tried to convert it from php to c# my attempt to convert it... failed very badly:
private string trimString(string str, int maxCharacters = 16)
{
int textLength = str.Length;
return str.Substring(maxCharacters/2, textLength-maxCharacters).Insert(maxCharacters/2,"...");
}
So doing trimString("123456789", 9) outputs 123...789 when I meant to do something like 123...012 or something similar.. I can't quite figure it out and I've tried many different versions mostly resulting in an input that is out of order.
If it's possible I'd like it to be a simple function and not include other libraries or initializing a new object every call as I plan on using this a lot in a quick session. I'd really like it not to cut off words and place the ellipses however this is not required.
The problem is that Substring(maxCharacters/2, textLength-maxCharacters) into which you insert the ... already has the characters that you don't want to see - 456789. There's no way to fix it after that.
What you should do instead is to pick the prefix and the suffix, and join them together, like this:
private static string trimString(string str, int maxCharacters = 16) {
if (str.Length <= maxCharacters) {
return str;
}
var suffixLength = maxCharacters / 2;
// When maxCharacters is odd, prefix will be longer by one character
var prefixLength = maxCharacters - suffixLength;
return string.Format(
"{0}...{1}"
, str.Substring(0, prefixLength)
, str.Substring(str.Length-suffixLength, suffixLength)
);
}
Demo.
this returns 123...012 for trimString("123456789012", 6) the first and the last 3 characters, seperated with ....
public static string trimString(string str, int max = 16)
{
if (str.Length <= max)
{
return str;
}
return str.Substring(0, max / 2) + "..." + str.Substring(str.Length - max / 2, max / 2);
}

How string quote, length total count and arrayname[int] work?

I'm making a program which reverses words to sdrow.
I understand that for it to work it needs to be written this way.
I'm more interested on WHY it has to be this way.
Here is my code:
Console.WriteLine("Enter a word : ");
string word = Console.ReadLine();
string rev = "";
int length;
for (length = word.Length - 1; length >= 0; length--)
{
rev = rev + word[length];
}
Console.WriteLine("The reversed word is : {0}", rev);
My questions are:
a) why you must use quotes to initialize your string
b) Why must you start your loop at one less than the total length of your string
c) How arrayname[int] works
I'm pretty new to C# and this site, as well. I hope my questions make sense and that I've asked them in the correct and proper way.
Thank you for your time!
This is how I've interpreted your question.
You want to know why you must use quotes to initialize your string
Why must you start your loop at one less than the total length of your string
How arrayname[int] works
I think that the best way to explain this to you is to go through your code, and explain what it does.
Console.WriteLine("Enter a word : ");
The first line of code prints Enter a word : into the console.
string word = Console.ReadLine();
This line "reads" the input from the console, and puts it into a string called word.
string rev = "";
This initiates a string called rev, setting it's value to "", or an empty string. The other way to initiate the string would be this:
string rev;
That would initiate a string called rev to the value of null. This does not work for your program because rev = rev + word[length]; sets rev to itself + word[length]. It throws an error if it is null.
The next line of your code is:
int length;
That sets an int (which in real life we call an integer, basically a number) to the value of null. That is okay, because it gets set later on without referencing itself.
The next line is a for loop:
for (length = word.Length - 1; length >= 0; length--)
This loop sets an internal variable called length to the current value of word.Length -1. The second item tells how long to run the loop. While the value of length is more than, or equal to 0, the loop will continue to run. The third item generally sets the rate of increase or decrease of your variable. In this case, it is length-- that decreases length by one each time the loop runs.
The next relevant line of code is his:
rev = rev + word[length];
This, as I said before sets rev as itself + the string word at the index of length, whatever number that is at the time.
At the first run through the for loop, rev is set to itself (an empty string), plus the word at the index of length - 1. If the word entered was come (for example), the index 0 would be c, the index 1 would be o, 2 would be m, and 3 = e.
The word length is 4, so that minus one is 3 (yay - back to Kindergarten), which is the last letter in the word.
The second time through the loop, length will be 2, so rev will be itself (e) plus index 2, which is m. This repeats until length hits -1, at which point the loop does not run, and you go on to the next line of code.
...Which is:
Console.WriteLine("The reversed word is : {0}", rev);
This prints a line to the console, saying The reversed word is : <insert value of rev here> The {0} is an internal var set by the stuff after the comma, which in this case would be rev.
The final output of the program, if you inserted come, would look something like this:
>Enter a word :
>come
>
>The reversed word is : emoc
a) you must to initialize or instantiate the variable in order to can work with it. In your case is better to use and StringBuilder, the string are inmutable objects, so each assignement means to recreate a new string.
b) The arrays in C# are zero index based so their indexes go from zero to length -1.
c) An string is an characters array.
Any case maybe you must to try the StringBuilder, it is pretty easy to use
I hope this helps
a) you need to initialize a variable if you want to use it in an assignment rev = rev + word[length];
b) you are using a for loop which means that you define a start number length = word.Length - 1, a stop criteria length >= 0 and a variable change length--
So lenght basically descends from 5 to 0 (makes 6 loops). The reason is that Arrays like 'string' a char[] are zerobased indexed.. means that first element is 0 last is array.Length - 1
c) So a string is basically a chain of char's.. with the []-Operator you can access a single index. The Return Type of words[index] is in this case a character.
I hope it helped
a) You need to first instantiate the string rev before you can assign it values in the loop. You could also say "string rev = String.Empty". You are trying to add word to rev and if you don't tell it first that rev is an empty string it doesn't know what it is adding word to.
b) The characters of the string have indexes to show which position they appear in the string. These indexes start at 0. So you're first character will have an index of 0. If the length of your string is 6 then the last character's index will be 5. So length - 1 will give you the value of the last character's index which is 5. A c# for loop uses the following parameters
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
where "int i = 0;" is the starting index; "i < 10" tells the loop when to stop looping; and "i++" tells it to increment i (the index) after each loop.
So in your code you are saying start at the last character of my string; perform this loop while there are still characters in the string; and decrease the index of the string after each loop so the next loop will look at the previous character in the string.
c) word[length] then in this scenario is saying add the character that has the position with index "length" to the rev string. This will basically reverse the word.
As usual you can do it in linq and avoid the (explicit) loops
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Enter a word : ");
string word = Console.ReadLine();
Console.WriteLine("The reversed word is : {0}", new string (word.Reverse().ToArray()));
Console.ReadLine();
}
}
}
var reversedWords = string.Join(" ",
str.Split(' ')
.Select(x => new String(x.Reverse().ToArray())));
Take a look here :
Easy way to reverse each word in a sentence

ArgumentOutOfRangeException when using lastIndexOf()

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

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