Mitja Bonca
Mitja Bonca

Reputation: 4546

String's method, like MiddleIndexOf - can it be done?

I know how to use string's method IndexOf and LastIndexOf. But I'm wondering if is it somehow possible to do in a "short way" with some kind of "MiddleIndexOf", so something in between IndexOf, and LastIndexOf.

To tell you what I mean, Best way is to show an example:

string str = @"1\2\3\4\5";

How would it be possbile to get part of upper string from 4 on (so "4\5"). It means I cannot use IndexOf, or LastIndexOf, but I would need something like "BeforeLastIndexOf" method.

Or not just that, lets say I want part of string from 3 on (so "3\4\5"). This even means I cannot use "BeforeLastIndexOf", but something different.

--

This would mean: 1 before LastIndexOf, or 2 before LastIndexOf (or maybe from front: 2 after IndexOf, or 3 after IndexOf).

--

I know I can split string by backslash delimiter, but I would like to know if there is any way to use a string methods (like explained).

Big thx in advance,

bye

Upvotes: 0

Views: 143

Answers (3)

Aidiakapi
Aidiakapi

Reputation: 6249

There's no MiddleIndexOf but both IndexOf and LastIndexOf allow you to choose a point to start the search from.

For example:

string str = @"1\2\3\4\5";
//    indexes: 012345678
int index = str.IndexOf('\\', 4);
// index = 5, it starts searching from: "3\4\5"

To get the index of the second slash, this is what you'd do:

string str = @"1\2\3\4\5";
int index = str.IndexOf('\\', str.IndexOf('\\') + 1);

To get the second last slash, this is the code:

string str = @"1\2\3\4\5";
int index = str.LastIndexOf('\\', str.LastIndexOf('\\') - 1);

To list every index of a character inside of a string, these extension methods can help:

public static int[] GetAllIndexes(this string @this, string substr)
{
    var indexes = new List<int>();
    int index = -1;
    while ((index = @this.IndexOf('\\', index + 1)) >= 0) indexes.Add(index);
    return indexes.ToArray();
}
public static int[] GetAllIndexes(this string @this, char substr)
{
    var indexes = new List<int>();
    int index = -1;
    while ((index = @this.IndexOf('\\', index + 1)) >= 0) indexes.Add(index);
    return indexes.ToArray();
}

It can be used like this:

string str = @"1\2\3\4\5";
int[] indexes = str.GetAllIndexes('\\');

The BeforeLastIndexOf function you described could look like this:

public static int BeforeLastIndexOf(this string @this, string substr, int beforeCount)
{
    int index = @this.LastIndexOf(substr, @this.Length - 1);
    for (int i = 0; i < beforeCount && index >= 0; i++)
        index = @this.LastIndexOf(substr, index - 1);
    return index;
}
public static int BeforeLastIndexOf(this string @this, char substr, int beforeCount)
{
    int index = @this.LastIndexOf(substr, @this.Length - 1);
    for (int i = 0; i < beforeCount && index >= 0; i++)
        index = @this.LastIndexOf(substr, index - 1);
    return index;
}

You'd use it like:

string str = @"1\2\3\4\5";
//    indexes: 0123456789
int index = str.BeforeLastIndexOf('\\', 2);

It'd return 2 indexes before the last one. In this case it'd return 3. (\5 is the last one then \4 then \3, the index of the \ before \3 is 3).


You can do the same with IndexOf and make an AfterIndexOf:

public static int AfterIndexOf(this string @this, string substr, int afterCount)
{
    int index = @this.IndexOf(substr);
    for (int i = 0; i < afterCount && index >= 0; i++)
        index = @this.IndexOf(substr, index + 1);
    return index;
}
public static int AfterIndexOf(this string @this, char substr, int afterCount)
{
    int index = @this.IndexOf(substr);
    for (int i = 0; i < afterCount && index >= 0; i++)
        index = @this.IndexOf(substr, index + 1);
    return index;
}

You can use it like this:

string str = @"1\2\3\4\5";
//    indexes: 0123456789
int index = str.AfterIndexOf('\\', 2);

This in turn returns 5, the \ before 4.


To really get the MiddleIndexOf, or with other words, the index closest to the middle, you can use this extension method:

public static int MiddleIndexOf(this string @this, string substr, bool roundUp = false, bool preferUp = true)
{
    // Determine the middle character
    int middlePoint = (roundUp ? @this.Length : @this.Length - 1) / 2;

    // Find the indexes closest to the middle
    int indexBelow = @this.LastIndexOf(substr, middlePoint);
    int indexAbove = @this.IndexOf(substr, middlePoint);
    if (indexBelow < 0) return indexAbove;
    if (indexAbove < 0) return indexBelow;

    int diffBelow = middlePoint - indexBelow;
    int diffAbove = indexAbove - middlePoint;

    return diffAbove == diffBelow ? (preferUp ? indexAbove : indexBelow) : // If it's the same difference
        (diffAbove < diffBelow ? indexAbove : indexBelow); // Otherwise return the closest index
}
public static int MiddleIndexOf(this string @this, char substr, bool roundUp = false, bool preferUp = true)
{
    // Determine the middle character
    int middlePoint = (roundUp ? @this.Length : @this.Length - 1) / 2;

    // Find the indexes closest to the middle
    int indexBelow = @this.LastIndexOf(substr, middlePoint);
    int indexAbove = @this.IndexOf(substr, middlePoint);
    if (indexBelow < 0) return indexAbove;
    if (indexAbove < 0) return indexBelow;

    int diffBelow = middlePoint - indexBelow;
    int diffAbove = indexAbove - middlePoint;

    return diffAbove == diffBelow ? (preferUp ? indexAbove : indexBelow) : // If it's the same difference
        (diffAbove < diffBelow ? indexAbove : indexBelow); // Otherwise return the closest index
}

You can use it like so:

string str = @"1\2\3\4\5\";
int index = str.MiddleIndexOf('\\');

There's two optional parameters:

  • roundUp: If it's set to true, and you have an even amount of characters, it'll round up, otherwise it'd round down. For example, if you have 8 characters: "12345678" it'll choose 4 as middlepoint if roundUp is false, otherwise 5.
  • preferUp: When there's a character just as many characters away from the middlepoint later in the string as earlier in the string this'll determine which one it chooses. By default it is set to true to compensate for rounding down. (If you have a string of 8 characters "\1\2\3\4" the middlepoint should be at 3.5, but because this isn't possible it'll search from index 3. Index 3 is '2' a \ is just as far away below as above. But due to this being true, it'll choose the character at index 4 which is 0.5 far away from the middlepoint, otherwise it'd choose index below, which would be 1.5 far away from the real middlepoint.)

Upvotes: 3

JG in SD
JG in SD

Reputation: 5607

If you know the index of the first character, you can use string.IndexOf(value, startIndex) to start searching for the next instance after the first.

This code will get the index of the second character:

public int static SecondIndexOf(this string str, char value)
{
    var firstIndex = str.IndexOf(char);
    if (firstIndex == -1)
        return firstIndex;

    return str.IndexOf(char, firstIndex + 1);
}

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564403

You can supply a starting point to String.IndexOf(string, Int32). If the resulting index is beyond your "end point", there is nothing existing in between.

For example, given your string:

string str = @"1\2\3\4\5";

If you wanted to limit to @"4\5" and find the index of the slash:

int index = str.IndexOf(@"\", 6); // Start at char 6, returns 7

Upvotes: 1

Related Questions