1

I have a string that looks like this. It's not JSON and not XML.

{Foo={name=My Foo Value, active=true, some date=20170630}, Bar={name=My Bar Value}, Key With Space={name=Foo Bar, active=false}}

Here are the assumptions:

  1. Objects are enclosed by {}
  2. Keys can have a space in the name
  3. Keys are separated by a space and a comma (,)
  4. Values are assigned to keys by an equal sign
  5. Keys can have multiple values and values are enclosed by {}, values inside the value are separated by a space and a comma (,). For example, this is a single key with three values: {My Foo Key={one=true, two=true, third value=false}}

My strategy is to deserialize to Dictionary<string, object at first, worry about recursion later. Any suggestions (existing library?) appreciated!

Here is what I have

var stringContentTrimmed = stringContent.Substring(1, stringContent.Length - 2);
var objects = stringContentTrimmed.Split(',')
    .Select(x => x.Trim())
    .Where(x => !String.IsNullOrWhiteSpace(x));

TLDR. The Split function is also splitting up my values, which isn't what I want.

enter image description here

9
  • It could help if you could provide the class you want to populate from this string... Commented Jul 25, 2017 at 15:38
  • @ZoharPeled Keys and values vary greatly; I can't make any assumptions as to what keys will be populated, or any datatype assumptions. Commented Jul 25, 2017 at 15:39
  • so you want to create dynamic classes? how do plan on using the data? seems to me like this is a simple key-value collection, where the value itself might also be a key-value collection... Commented Jul 25, 2017 at 15:43
  • Correct. Hence the deserializing to Dictionary<string, object>. I'll use it later as mydict.TryGetValue("Foo", out fooValue). Commented Jul 25, 2017 at 15:46
  • Where did you get this string? Can you control the format? Do you have to do this lots of times or just once? Commented Jul 25, 2017 at 15:46

2 Answers 2

2

Really you need to have a proper specification or grammar for this but I'm going to take a wild guess and say that there isn't one, and if there was, actual values would not conform to it.

Your best bet might be:

  • Eliminate any whitespace adjacent to = { } or , characters
  • Replace any , with ","
  • Replace any = with "="
  • replace any { with {"
  • replace any } with "}
  • replace any "{ with {
  • replace any }" with }
  • replace any = with :

Then treat as JSON.

I tried this with your example and it worked. Whether it will work with your actual values I have no idea - this will depend on whether they stick to the restrictions you have described. If keys or values embed any of "{}:=, or if leading or trailing spaces are significant, then it will not work.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I tried this and it worked for me too. I accepted the other answer because it is more direct answer to my question and it doesn't require me to replace strings.
1

I created a method GetObjects below which returns a Dictionary<string, string> of the top-level objects and the raw content inside. Another method, Merge returns a nested dictionary by calling GetValues to extract the key-value pairs from the object content.

Using your example string, the Merge method returns this: enter image description here

class Program
{
    static void Main(string[] args)
    {
        var str = "{Foo={name=Foo Value, active=true, some date=20170630}, Bar={name#=My Bar Value}, Key With Space={name=Foo Bar, active=false}}";

        var values = GetObjects(str);

        Dictionary<string, Dictionary<string, string>> objects = Merge(values);
    }

    public static Dictionary<string, Dictionary<string, string>> Merge(Dictionary<string, string> input)
    {
        var output = new Dictionary<string, Dictionary<string, string>>();

        foreach (var key in input.Keys)
        {
            var value = input[key];
            var subValues = GetValues(value);

            output.Add(key, subValues);
        }

        return output;
    }

    public static Dictionary<string, string> GetObjects(string input)
    {
        var objects = new Dictionary<string, string>();
        var objectNames = new Queue<string>();
        var objectBuffer = string.Empty;

        foreach (var c in input)
        {
            if (char.Equals('{', c))
            {
                if (!string.IsNullOrEmpty(objectBuffer))
                {
                    var b = objectBuffer.Trim('{', '}', ',', ' ', '=');
                    objectNames.Enqueue(b);
                }

                objectBuffer = string.Empty;
            }

            if (char.Equals('}', c))
            {
                if (objectNames.Count > 0)
                {
                    var b = objectBuffer.Trim('{');
                    var key = objectNames.Dequeue();

                    objects.Add(key, b);
                }

                objectBuffer = string.Empty;
            }

            objectBuffer += c;
        }

        return objects;
    }

    private static Dictionary<string, string> GetValues(string input)
    {
        var output = new Dictionary<string, string>();
        var values = input.Split(new string[] { ", " }, System.StringSplitOptions.None);

        foreach (var val in values)
        {
            var parts = val.Split('=');
            if (parts.Length == 2)
            {
                var key = parts[0].Trim(' ');
                var value = parts[1].Trim(' ');
                output.Add(key, value);
            }
        }

        return output;
    }
}

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.