user5405648
user5405648

Reputation:

ArgumentOutOfRangeException: extracting string from string

I have a method that extracts a username from a string using conditionals to check common conventions, although it is resulting in an ArgumentOutOfRangeException on the GetPart utility method, even after explicitly checking before calling it?

Here is the extraction method

public bool TryExtractUsernameFromString(string str, out string username)
{
    if (str.Contains("un: "))
    {
        username = GetPart(str, "un: ", " ");
    }
    else if (str.Contains("un:"))
    {
        username = str.Split(" ").Where(x => x.StartsWith("un:")).First().Substring(3);
    }
    else if (str.Contains("un- "))
    {
        username = str.IndexOf(" ", str.IndexOf("un- ") + 1) > 0 ? GetPart(str, "un- ", " ") : str[str.IndexOf("un- ")..str.Length];
    }
    else if (str.Contains("un-"))
    {
        username = str.Split(" ").Where(x => x.StartsWith("un-")).First().Substring(3);
    }
    else
    {
        username = "";
    }

    return username.Length > 0;
}

I am passing this as the first argument to TryExtractUsernameFromString (without quotes)

"😊un- jennyfromtheblock"

So it happens here,

else if (str.Contains("un- "))
{
    username = str.IndexOf(" ", (str.IndexOf("un- ") + 1)) > 0 ? GetPart(str, "un- ", " ") : str[str.IndexOf("un -")..str.Length];
}

But shouldn't be calling GetPart() if it doesn't contain a second space after the first one in the str.Contains check.

GetPart method:

public static string GetPart(string s, string start, string end)
{
    return s[(s.IndexOf(start) + start.Length)..s.IndexOf(end)];
}

Upvotes: 0

Views: 81

Answers (2)

Austin T French
Austin T French

Reputation: 5140

@DanRayson looks correct; But I wanted to add there is likely a much cleaner approach to this.

If statements can suck, case statements aren't really better. If you assume any name could have 0 or more matches:

public static void CleanName(string nameString, List<string> badPrefixes)
{
    var matchedPrefixes = badPrefixes.Where(w => nameString.Contains(w) 
               && && nameString.IndexOf(w) == 0).ToList();
    foreach(var prefix in matchedPrefixes)
    {
        Console.WriteLine(nameString.Replace(prefix, "").Trim());
    }   

    if (!matchedPrefixes.Any())
    {
       Console.WriteLine(nameString);
    }
}

Another option would be using .FirstOrDefault instead of selecting all of the matches. But essentially, just find the match(es) and then remove it, and finally trim spaces.

Example

public static void Main()
{
    List<string> badPrefixes = new List<string>()
    {
       "un:",
        "un-",
        "un ",  
        "Un", //Fun example too     
    };
    
    string longUserName1 = "un- Austin";
    string riskyLongName = "un: theUndying";
    
    CleanName(longUserName1, badPrefixes);
    // output: Austin
    CleanName(riskyLongName, badPrefixes);
    // output: theUndying
}

Upvotes: 0

Dan Rayson
Dan Rayson

Reputation: 1437

str.IndexOf("un- ") + 1 is returning the index of the START + 1 of that substring. Try using str.IndexOf("un- ") + 4 instead. That'll get you the index of the second space you're looking for.

Upvotes: 2

Related Questions