Reputation: 643
is there a command that can get the third index of a character in a string? For example:
error: file.ext: line 10: invalid command [test:)]
In the above sentence, I want to the index of the 3rd colon, the one next to the 10. How could I do that? I know of string.IndexOf and string.LastIndexOf, but in this case I want to get the index of a character when it is used the third time.
Upvotes: 14
Views: 36811
Reputation: 3096
Simply split the string by the char. This gives you an array that you can then use to target what you want.
var stringToSplit = "one_two_three_four";
var splitString = stringToSplit.Split("_");
if (splitString.length > 3){
var newString = $"{splitResult[0]}_{splitResult[1]}_{splitResult[2]}";
}
Upvotes: 0
Reputation: 996
Please see this answer on a similar question:
https://stackoverflow.com/a/46460083/7673306
It provides a method for you to find the index of nth occurrence of a specific character within a designated string.
In your specific case it would be implemented like so:
int index = IndexOfNthCharacter("error: file.ext: line 10: invalid command [test:)]", 3, ':');
Upvotes: 0
Reputation:
This has already been answered several very good ways - but I decided to try and write it using Expressions.
private int? GetNthOccurrance(string inputString, char charToFind, int occurranceToFind)
{
int totalOccurrances = inputString.ToCharArray().Count(c => c == charToFind);
if (totalOccurrances < occurranceToFind || occurranceToFind <= 0)
{
return null;
}
var charIndex =
Enumerable.Range(0, inputString.Length - 1)
.Select(r => new { Position = r, Char = inputString[r], Count = 1 })
.Where(r => r.Char == charToFind);
return charIndex
.Select(c => new
{
c.Position,
c.Char,
Count = charIndex.Count(c2 => c2.Position <= c.Position)
})
.Where(r => r.Count == occurranceToFind)
.Select(r => r.Position)
.First();
}
and Tests to prove it too:
Assert.AreEqual(0, GetNthOccurrance(input, 'h', 1));
Assert.AreEqual(3, GetNthOccurrance(input, 'l', 2));
Assert.IsNull(GetNthOccurrance(input, 'z', 1));
Assert.IsNull(GetNthOccurrance(input, 'h', 10));
Upvotes: 2
Reputation: 4929
Here is a recursive implementation (for string not char) - as an extension method, mimicing the format of the framework method(s).
All you need to do is change 'string value' to 'char value' in the extension method and update the tests accordingly and it will work... I'm happy to do that and post it if anyone is interested?
public static int IndexOfNth(
this string input, string value, int startIndex, int nth)
{
if (nth < 1)
throw new NotSupportedException("Param 'nth' must be greater than 0!");
if (nth == 1)
input.IndexOf(value, startIndex);
return
input.IndexOfNth(value, input.IndexOf(value, startIndex) + 1, --nth);
}
Also, here are some (MBUnit) unit tests that might help you (to prove it is correct):
[Test]
public void TestIndexOfNthWorksForNth1()
{
const string input = "foo<br />bar<br />baz<br />";
Assert.AreEqual(3, input.IndexOfNth("<br />", 0, 1));
}
[Test]
public void TestIndexOfNthWorksForNth2()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(21, input.IndexOfNth("<br />", 0, 2));
}
[Test]
public void TestIndexOfNthWorksForNth3()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(34, input.IndexOfNth("<br />", 0, 3));
}
Upvotes: 0
Reputation: 19781
I am guessing you want to parse that string into different parts.
public static void Main() {
var input = @"error: file.ext: line 10: invalid command [test (: ]";
var splitted = input .Split(separator: new[] {": "}, count: 4, options: StringSplitOptions.None);
var severity = splitted[0]; // "error"
var filename = splitted[1]; // "file.ext"
var line = splitted[2]; // "line 10"
var message = splitted[3]; // "invalid command [test (: ]"
}
Upvotes: 4
Reputation: 17247
A little ugly, but an alternative approach (to the others already posted) that works:
public int FindThirdColonIndex(string msg)
{
for (int i = 0, colonCount = 0; i < msg.Length; i++)
{
if (msg[i] == ':' && ++colonCount == 3) { return i; }
}
// Not found
return -1;
}
Upvotes: 0
Reputation: 108975
String.IndexOf
will get you the index of the first, but has overloads giving a starting point. So you can use a the result of the first IndexOf
plus one as the starting point for the next. And then just accumulate indexes a sufficient number of times:
var offset = myString.IndexOf(':');
offset = myString.IndexOf(':', offset+1);
var result = myString.IndexOf(':', offset+1);
Add error handling unless you know that myString
contains at least three colons.
Upvotes: 16
Reputation: 13019
You could write something like:
public static int CustomIndexOf(this string source, char toFind, int position)
{
int index = -1;
for (int i = 0; i < position; i++)
{
index = source.IndexOf(toFind, index + 1);
if (index == -1)
break;
}
return index;
}
EDIT: Obviously you have to use it as follows:
int colonPosition = myString.CustomIndexOf(',', 3);
Upvotes: 12
Reputation: 4341
int pos = -1;
for ( int k = 0; k < 3; ++k )
{
pos = s.indexOf( ':', pos+1 );
// Check if pos < 0...
}
Upvotes: 0
Reputation: 14160
You can call .IndexOf(char, position) to search from desired position, thus you should call it 3 times (but, after each call you should also check if something is found).
Upvotes: 0