tags:

views:

564

answers:

9

string format is always like this "FirstName=ABC;LastName=XZY;Username=User1;Password=1234".

I need the only UserName value (which is 'User1' in this case). I wanna achieve this in minimum line of code using substring method (or something else).

Help?

+11  A: 

Looks like a delimited string, so this would work:

string result = myString.Split(';')[2].Split('=')[1];

However, if someone changes the value pair order, this will break.

There are better ways about this, that will not break if the order changes, the number of parameters is different etc - such as the Regular Expression as Michael posted, or the Linq queries posted by a number of people.

Oded
beat me to it :(
Stan R.
I appreciate that you were attempting to make it as short as possible, but I think we have the winner for the ugliest piece of code I've seen recently. (No offense intended!)
brian
I wouldn't say its the ugliest code ever, but the user got what he wanted.....
Stan R.
@user: I suggest you sign up with a real name - I'm beginning to recognize you by the digits in your user id. :-)
John Saunders
+4  A: 

Least number of lines of code is not always the best metric, but you could do what you need with Regex.

brian
How odd, this is probably one of the first times I've ever seen a regex suggested and it be a valid answer. :p
Tanzelax
Haven't you heard - Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. Jamie Zawinski
Oded
@Tanzelax: Regex becoming the new JQuery?
brian
I like how this is an answer, i should go around telling everyone to use C# as my answer. I am sorry, but simply saying you could do what you need with Regex is not a valid answer. Supply a code example.
Stan R.
@Stan R: I am agree with you at least being new to programming...Sample Code helps a lot...
Novice
+1  A: 
        string t = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";
        string name = t.Split(';')[2].Split('=')[1];
Stan R.
+3  A: 

This method will work even if the value-pairs are given in a different order. It splits on the semicolon, finds the item with "Username", then returns what's after the equal sign.

string theString = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";
string username = theString.Split(";").Where(s => s.Split("=")[0].Equals("Username")).ToArray()[0].Split("=")[1];
Aaron
@Aaron: Sorry to ask, is syntax oke. I am getting error near .ToArray[0]..??
Novice
@user144842: You caught an error in my example! There are supposed to be parentheses after ToArray. I have updated my answer.
Aaron
That would be half VB and half C# ... probably all off the top of his head.
Matthew Whited
Your suggestion is most suitable for me for now. Just Edit last [0] to [1] in your answer statment. Thanks.
Novice
Done. Thank you.
Aaron
+7  A: 

Here is an alternative solution (not too different from others, but which I think is more straightforward) which will work regardless of order.

var input = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";

Assert.AreEqual("User1", input
    .Split(';')
    .Select(item => item.Split('='))
    .Where(pair => pair[0].Equals("Username"))
    .Single()[1]);
Daniel Straight
Fails when there is no "Username" at the string.
Bruno Brant
If there might not be a username, you could add `.Select(pair => pair[1])` before `.Single()` and change `.Single()` to `.SingleOrDefault()`. Then you just get null if there is no username.
Daniel Straight
+14  A: 

For the sake of completeness, here is the Regex way of doing it. This will also work if the order changes.

// using System.Text.RegularExpressions;

string test1 = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";
string test2 = "FirstName=ABC;LastName=XZY;Password=1234;Username=User1";
string test3 = "FirstName=ABC;LastName=XZY;Password=1234";

string regexPattern = @"(?<=Username=)[^;\n]*";
var userName1 = Regex.Match(test1, regexPattern).Value; // User1
var userName2 = Regex.Match(test2, regexPattern).Value; // User1
var userName3 = Regex.Match(test3, regexPattern).Value; // string.Empty

// Compiling can speed up the Regex, at the expense of longer initial Initialization
// Use when this is called often, but measure.

Regex compiledRx = new Regex(regexPattern,RegexOptions.Compiled);
var userNameCompiled1 = compiledRx.Match(test1).Value; // User1
var userNameCompiled2 = compiledRx.Match(test2).Value; // User1
var userNameCompiled3 = compiledRx.Match(test3).Value; // string.Empty
Michael Stum
This is actually a good place to apply regexes. Good stuff.
Daniel Straight
+3  A: 

While the split answers are 'ok' if nothing ever changes, it's probably better to use a function because:

  • It makes your intentions clear.
  • It is easier to document.
  • It is easier to modify should the inevitable happen.
  • Works regardless of order.

(Even if you just put the one line split in the function! or at the very least add a comment to the split.)


static String GetUsername(String value)
{
    String result = "";
    String token = "Username=";

    int index = value.IndexOf(token) + token.Length;
    while (value[index] != ';')
    {
        result += value[index++];
        if (index > value.Length - 1)
            break;
    }

    return result;
}
I like the suggestion to encapsulate this "logic", but let's be evil: His sample didn't end in a ';'. Now imagine the "Username=" part is at the end, what would happen with your solution?
Benjamin Podszun
@Benjamin - While not difficult to handle that case; I think all solutions presented suffer from some deficiency. For example, what if there were two usernames in the string? What would happen? This solution would always pick the first. At any rate, I think this trivial problem has been taken to an extreme.
Agreed - and +1 for that :)
Benjamin Podszun
+3  A: 

Not as simple as using split, however:

string input = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";
string username = Regex.Match(input, "Username=(?<username>.*?)(;|$)").Groups["username"].Value;

In this case, groups can be in any order.

And, if you like to get creative:

var answers = from tuple in input.Split(';')
              where tuple.StartsWith("Username=")
              select tuple.Split('=')[1];

username = answers.Count() > 0 ? answers.First() : string.Empty;

One might say the last piece has better semantics.

EDIT: Update the last piece to deal with input strings that doesn't have the required tuple.

Bruno Brant
Would fail if the source string is `FirstName=ABC;Username=User1;LastName=XZY;Password=1234`. Use the `?` for a lazy search: `Username=(?<username>.*?);`
Naeem Sarfraz
@Naeem Sarfraz: Thanks, you're right. Damn greedy thing. Also, I correted the case in which the Username is the last pair in the string. And now the REGEX is way complex...
Bruno Brant
+1  A: 

This isn't the shortest... but probably one of the fastest.

string value = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234";
int offset = value.IndexOf("Username=") + 9;
if (offset < 9)
    throw new Exception("Username= not found in string");
int len = value.IndexOf(';', offset) - offset;
if (len < 0)
    len = value.Length - offset;
string find = value.Substring(offset, len);

... the if (len < 0) is for is the Username is at the end of the string and doesn't end with a semicolon. If you want to ignore case you can replace the int offset line with this...

int offset = value.ToUpperInvariant().IndexOf("USERNAME=") + 9;
Matthew Whited
I know the "magic number" could be replaced by moving "Username=" to a variable such as token and using token.Length.
Matthew Whited
Feel free to complain about "Exception" I didn't feel like anything better for an example.
Matthew Whited