2

My string:

string str = "user:steo id:1 nickname|user:kevo id:2 nickname:kevo200|user:noko id:3 nickname";

Now I want to get the values out with Regex:

var reg = Regex.Matches(str, @"user:(.+?)\sid:(\d+)\s+nickname:(.+?)")
          .Cast<Match>()
          .Select(a => new
          {
              user = a.Groups[1].Value,
              id = a.Groups[2].Value,
              nickname = a.Groups[3].Value
           })
           .ToList();
foreach (var ca in reg)
{
    Console.WriteLine($"{ca.user} id: {ca.id} nickname: {ca.nickname}");
}  

I do not know how I can do it with regex that I can use nickname:(the nickname) I only want use the nickname if it has a nickname like nickname:kevo200 and noch nickname

2
  • I'm not entirely sure about the structure of the string. Does it always contain the field nickname, but the value for nickname may be empty? If the nickname is empty is this denoted as nickkname| or nickname:| What do you want to do with users, which don't have a nickname? Commented Aug 25, 2018 at 10:48
  • A plus sign indicates one or more while an asterisk indicates zero or more. I would replace the +? with . I think it is better to use \w where 'w' is a word character instead of the do which is every character. Commented Aug 25, 2018 at 12:19

4 Answers 4

1

I am not a 100% sure if this answers your question, but i fetched a list from the given input string via regex parsing and either return the nick when available or the username otherwise.

PS C:\WINDOWS\system32> scriptcs
> using System.Text.RegularExpressions;
> var regex = new Regex(@"\|?(?:user(?::?(?<user>\w+))\sid(?::?(?<id>\d*))\s?nickname(?::?(?<nick>\w+))?)");
> var matches = regex.Matches("user:steo id:1 nickname|user:kevo id:2 nickname:kevo200|user:noko id:3 nickname");
> matches.Cast<Match>().Select(m=>new {user=m.Groups["user"].Value,nick=m.Groups["nick"].Value}).Select(u=>string.IsNullOrWhiteSpace(u.nick)?u.user:u.nick);
[
  "steo",
  "kevo200",
  "noko"
]

edit: regex designer: https://regexr.com/3uf8t

edit: improved version to accept escape sequences in nicknames

PS C:\WINDOWS\system32> scriptcs
> using System.Text.RegularExpressions;
> var regex = new Regex(@"\|?(?:user(?::(?<user>\w+))?\sid(?::(?<id>\d*))?\s?nickname(?::(?<nick>[\w\\]+))?)");
> var matches = regex.Matches("user:steo id:1 nickname|user:kevo id:2 nickname:kevo200|user:noko id:3 nickname|user:kevo id:2 nickname:kev\\so200");
> matches.Cast<Match>().Select(m=>new {user=m.Groups["user"].Value,nick=m.Groups["nick"].Value.Replace("\\s"," ")}).Select(u=>string.IsNullOrWhiteSpace(u.nick)?u.user:u.nick);
[
  "steo",
  "kevo200",
  "noko",
  "kev o200"
]
Sign up to request clarification or add additional context in comments.

2 Comments

if the nickname has a \s it does not work example: nickname:stev\shans the \s is a whitespace I think its the \w+
when this is your only escape sequence, this should work: \|?(?:user(?::?(?<user>\w+))\sid(?::?(?<id>\d*))\s?nickname(?::?(?<nick>[\w\\]+))?) you have to replace it in the nickname afterwards of cause... it will also work with other `\` prefixed escapes...
0

Try this: user:(.+?)\sid:(\d+)\s+nickname:*(.*?)(\||$).

At first I proposed this regex: user:(.+?)\sid:(\d+)\s+nickname:*(.*?)\|* – wrong, doesn't capture name because of lazy quantifier.

Then this regex expression: user:(.+?)\sid:(\d+)\s+nickname(:(.+?)|)(\||$) – this should match all the parts divided by '|' in your string and give nickname="" for empty nicknames. But in case Groups[4] is not defined (when nickname is not followed by ":") you'll need check on the value existence.

7 Comments

* denotes "0 or more". Do you expect the string to look like "nickname::::::" or "nickname:abc|||||||||"?
Based on the above example, the : after nickname is only present, when there is a value for nickname. Furthermore, the * is a greedy operator, so at least the last one will match anything after the first user ...
@pinkfloydx33 Of course not, though it all depends on user input check. I assumed avoid using (:|) and (\||) constructions to correct and clear grouping.
Your answer is not far from the solution, but now I can not get the content out of the nickname: regexr.com/3ufbk
I'd use nickname:? instead of nickname:*
|
0

If it were up to me and the data you are processing is always pipe separated and in a constant order, I would probably just skip the regex and split the string into it's pieces using String.Split like this.

string str = "user:steo id:1 nickname|user:kevo id:2 nickname:kevo200|user:noko id:3 nickname";
var entries = str.Split('|');
foreach(var entry in entries)
{
    var subs = entry.Split(' ');
    var userName = subs[0].Split(':')[1];
    var id = subs[1].Split(':')[1];
    var tempNick = subs[2].Split(':');
    var nick = tempNick.Length == 2 ? tempNick[1] : string.Empty;
    Console.WriteLine(userName + " id:" + id + " nickname " + nick);
}

3 Comments

Oops! Didn't see your answer! I've packed everything into more readable LINQ. :)
@JohnyL - I might argue on the "packed" and "readability" side since you accomplished in 15 lines what I did in 8 ;)
Well, you cheated a bit) For instance, anonymous type creation could be done in one line. Indeed, I could write all the code in one line. How many semicolons do you have? :) :) The thing is that my code is functional, but yours - procedural. You extract data and output at the same time, while my code could be packed into separate method. To summarize, getting data and outputting it could take two lines. :)
0

Without Regex:

static void GetInfo()
{
    string input = @"user:steo id:1 nickname|user:kevo id:2 nickname:kevo200|user:noko id:3 nickname";

    var users =
        from info in input.Split('|')
        let x = info.Split(" ")
        let nick_split = x[2].Split(':')
        let has_nick = nick_split.GetUpperBound(0) > 0
        let z = new
        {
            User = x[0].Split(':')[1],
            Id = x[1].Split(':')[1],
            Nickname = has_nick ? nick_split[1] : String.Empty
        }
        select z;

    foreach (var user in users)
    {
        Console.WriteLine($"user: {user.User}, id: {user.Id}, nickname: {user.Nickname}");
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.