Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need some help on a Regex match / replace pattern

Tags:

c#

regex

My ultimate goal here is to turn the following string into JSON, but I would settle for something that gets me one step closer by combining the fieldname with each of the values.

Sample Data:

Field1:abc;def;Field2:asd;fgh;

Using Regex.Replace(), I need it to at least look like this:

Field1:abc,Field1:def,Field2:asd,Field2:fgh

Ultimately, this result would be awesome if it can be done via Regex in a single call.

{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"}

I've tried many different variations of this pattern, but can't seem to get it right:

(?:(\w+):)*?(?:([^:;]+);)

Only one other example I could find that is doing something similar, but just enough differences that I can't quite put my finger on it.

Regex to repeat a capture across a CDL?

EDIT:

Here's my solution. I'm not going to post it as a "Solution" because I want to give credit to one that was posted by others. In the end, I took a piece from each of the posted solutions and came up with this one. Thanks to everyone who posted. I gave credit to the solution that compiled, executed fastest and had the most accurate results.

    string hbi = "Field1:aaa;bbb;ccc;ddd;Field2:111;222;333;444;";

    Regex re = new Regex(@"(\w+):(?:([^:;]+);)+");
    MatchCollection matches = re.Matches(hbi);

    SortedDictionary<string, string> dict = new SortedDictionary<string, string>();

    for (int x = 0; x < matches.Count; x++)
    {
        Match match = matches[x];
        string property = match.Groups[1].Value;

        for (int i = 0; i < match.Groups[2].Captures.Count; i++)
        {
            string key = i.ToString() + x.ToString();
            dict.Add(key, string.Format("\"{0}\":\"{1}\"", property, match.Groups[2].Captures[i].Value));
        }
    }
    Console.WriteLine(string.Join(",", dict.Values));
like image 333
Chris Gessler Avatar asked Oct 08 '22 14:10

Chris Gessler


2 Answers

Now you have two problems

I don't think regular expressions will be the best way to handle this. You should probably start by splitting on semicolons, then loop through the results looking for a value that starts with "Field1:" or "Field2:" and collect the results into a Dictionary.

Treat this as pseudo code because I have not compiled or tested it:

string[] data = input.Split(';');
dictionary<string, string> map = new dictionary<string, string>();

string currentKey = null;
foreach (string value in data)
{
    // This part should change depending on how the fields are defined.
    // If it's a fixed set you could have an array of fields to search,
    // or you might need to use a regular expression.
    if (value.IndexOf("Field1:") == 0 || value.IndexOf("Field2:"))
    {
        string currentKey = value.Substring(0, value.IndexOf(":"));
        value = value.Substring(currentKey.Length+1);
    }
    map[currentKey] = value;
}
// convert map to json
like image 128
mcrumley Avatar answered Oct 12 '22 10:10

mcrumley


I had an idea that it should be possible to do this in a shorter and more clear way. It ended up not being all that much shorter and you can question if it's more clear. At least it's another way to solve the problem.

var str = "Field1:abc;def;Field2:asd;fgh";
var rows = new List<Dictionary<string, string>>();
int index = 0;
string value;
string fieldname = "";

foreach (var s in str.Split(';'))
{
    if (s.Contains(":"))
    {
        index = 0;
        var tmp = s.Split(':');
        fieldname = tmp[0];
        value = tmp[1];
    }
    else
    {
        value = s;
        index++;
    }

    if (rows.Count < (index + 1))
        rows.Insert(index, new Dictionary<string, string>());

    rows[index][fieldname] = value;
}

var arr = rows.Select(dict => 
                   String.Join("," , dict.Select(kv => 
                       String.Format("\"{0}\":\"{1}\"", kv.Key, kv.Value))))
                   .Select(r => "{" + r + "}");
var json = String.Join(",", arr );
Debug.WriteLine(json);

Outputs:

{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"}
like image 27
Jonas Elfström Avatar answered Oct 12 '22 10:10

Jonas Elfström