1

I have the following string:

string myString = "{'gridObject':'[1,2,3,4],[5,6,7,8]'}";

How do I process this into an object so that I can do this:

charts[0]     //=> [1,2,3,4]
charts[0][1]  //=> 2

If I can convert it to this object, even better:

public class gridObject {

    public int datarow   {get; set;}
    public int datacol   {get; set;}
    public int datasizex {get; set;}
    public int datasizey {get; set;}

}
user990423
  • 1,397
  • 2
  • 12
  • 32
Ege Ersoz
  • 6,461
  • 8
  • 34
  • 53
  • 1
    The big problem you've got here is that you've got an obvious delimiter (the comma) at two levels in your input - separating the numbers **and** separating the sets of numbers. How much control do you have over the format of this data? Can you get it changed? – ChrisF Dec 02 '15 at 22:40
  • 1
    What have you tried? The outer object looks like JSON, so the value of the `gridObject` can be parsed separately. – CodeCaster Dec 02 '15 at 22:43
  • ChrisF: I have full control over the format. I can change the delimiters and everything else. – Ege Ersoz Dec 02 '15 at 22:47
  • You can use a JSON parsing library: once for the `myString` string itself, and then again on the string, by wrapping `[1,2,3,4],[5,6,7,8]` with extra square brackets to ensure it is a properly formed JSON string (of a 2D array). See http://stackoverflow.com/questions/6620165 – Jeff Meatball Yang Dec 02 '15 at 22:48
  • 1
    _" I have full control over the format"_ - make it fully valid JSON with arrays and all, then the parsing is trivial. – CodeCaster Dec 02 '15 at 22:49
  • OK, I can encode the data on the front-end like this: `{"chartObjects":[{"datarow":"1","datacol":"2","datasizex":"3","datasizey":"4"},{"datarow":"5","datacol":"6","datasizex":"7","datasize":"8"}]}`. JSLint says that's valid JSON. – Ege Ersoz Dec 02 '15 at 22:57

3 Answers3

3

This is what I would do.

Create your classes first,

public class GridObject
{
    public int datarow { get; set; }
    public int datacol { get; set; }
    public int datasizex { get; set; }
    public int datasizey { get; set; }
}

public class GridObjectCollection
{
    public GridObject[] GridObjects { get; set; }
}

Then, to see what JSON you need, serialize it once: (JsonConvert is part of Json.NET, you can get it with NuGet)

GridObjectCollection gridObjects = new GridObjectCollection();
gridObjects.GridObjects = new GridObject[]
{
    new GridObject() { datacol = 1, datarow = 2, datasizex = 3, datasizey = 4 },
    new GridObject() { datacol = 5, datarow = 6, datasizex = 7, datasizey = 8 }
};

Console.WriteLine
(
    JsonConvert.SerializeObject
    (
        gridObjects,
        new JsonSerializerSettings() { Formatting = Formatting.Indented }
    )
);

Here you can see that the valid JSON content which will produce these classes when deserialized is like:

{
  "GridObjects": [
    {
      "datarow": 2,
      "datacol": 1,
      "datasizex": 3,
      "datasizey": 4
    },
    {
      "datarow": 6,
      "datacol": 5,
      "datasizex": 7,
      "datasizey": 8
    }
  ]
}

Then, just try a deserialization just to make sure:

var f = JsonConvert.DeserializeObject<GridObjectCollection>
(
    "{'GridObjects':[{'datarow':2,'datacol':1,'datasizex':3,'datasizey':4},{'datarow':6,'datacol':5,'datasizex':7,'datasizey':8}]}"
);
Oguz Ozgul
  • 6,809
  • 1
  • 14
  • 26
  • Thanks! Unrelated question: is there a "sandbox" environment I can use to quickly test stuff like this without actually implementing it in my project and running the project? I'm looking for something like the browser's javascript console, in which you can just type statements and see how they get evaluated. I use Visual Studio 2015. – Ege Ersoz Dec 02 '15 at 23:08
  • +1 to @LucMorin. You can also copy your json to clipboard and in Visual Studio, in a class window, Edit -> Paste Special -> Paste JSON as Classes – Oguz Ozgul Dec 02 '15 at 23:16
  • @OguzOzgul Ahhh... nifty :) – Luc Morin Dec 02 '15 at 23:19
  • @LucMorin That would have saved me hours if I knew that before, it was there, hidden in the Edit menu since the release of VS 2012 :) – Oguz Ozgul Dec 02 '15 at 23:21
1

Here is one way to do it:

public static gridObject[] Parse(string str)
{
    int first = str.IndexOf("[");

    int last = str.LastIndexOf("]");

    str = str.Substring(first, last - first + 1);

    string[] big_parts = str.Split(new string[] {"[", "],[", "]"} , StringSplitOptions.RemoveEmptyEntries);


    return big_parts.Select(x =>
    {
        string[] small_parts = x.Split(',');

        return new gridObject()
        {
            datarow = Convert.ToInt32(small_parts[0]),
            datacol = Convert.ToInt32(small_parts[1]),
            datasizex = Convert.ToInt32(small_parts[2]),
            datasizey = Convert.ToInt32(small_parts[3]),

        };
    }).ToArray();
}

It first searches for the the first [ and the last ] and trims anything before [ and after ].

Then, it splits the string based on [, ],[, ].

This will give us 1,2,3,4 and 5,6,7,8 for your example.

Then for each one of them, we split based on , and convert the results into a gridObject object.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
0

Done with custom parsing:

public class GridObject
{
    public int datarow { get; set; }
    public int datacol { get; set; }
    public int datasizex { get; set; }
    public int datasizey { get; set; }
}

/// <summary>
/// MySuperObject class which holds a reference to inner array of integers
/// </summary>
public class MySuperObject
{
    public List<int> Items { get; set; } // Inner array of list of integers

    public MySuperObject()
    {
        Items = new List<int>();
    }

    public override string ToString()
    {
        // Need to override ToString to return something like "[1,2,3,4]"
        var result = "";
        foreach (var item in Items)
        {
            if (result.Length > 0)
                result += ",";
            result += item.ToString();
        }
        return string.Format("[{0}]", result);
    }

    /// <summary>
    /// Function to generate GridObject from existing set of integers
    /// </summary>
    public GridObject GetGridObject()
    {
        var result = new GridObject();
        if (Items.Count >= 1) result.datarow = Items[0];
        if (Items.Count >= 2) result.datacol = Items[1];
        if (Items.Count >= 3) result.datasizex = Items[2];
        if (Items.Count >= 4) result.datasizey = Items[3];
        return result;
    }
}

// Parse functions
public List<MySuperObject> Parse(string value)
{
    if (string.IsNullOrEmpty(value))
        throw new ArgumentException("value cannot be null or empty!", "value");

    var result = new List<MySuperObject>();

    // First get the indexes of first [ and last ]
    var idxStart = value.IndexOf("[");
    var idxEnd = value.LastIndexOf("]");
    // Check validity
    if (idxStart < 0 || idxEnd < 0 || idxEnd <= idxStart)
        return result; // Return empty list

    value = value.Substring(idxStart, idxEnd - idxStart + 1).Trim();

    // Split by [] after replacing spaces with empty strings (and removing first and last [ and ])
    var arr = value.Replace(" ", "").Trim('[',']').Split(new[] { "],[" }, StringSplitOptions.RemoveEmptyEntries);
    foreach (var str in arr)
    {
        // Construct list of integers with a help of LINQ
        var nums = str.Split(',').Select(t => Convert.ToInt32(t)).ToList();

        // Create and add MySuperObject to existing list which will be returned
        result.Add(new MySuperObject
        {
            Items = new List<int>(nums),
        });
    }

    return result;
}

And here is the usage of such parsing:

var myString = "{'gridObject':'[1,2,3,4],[5,6,7,8]'}";
var value = Parse(myString);
// Get all grid objects
var allGridObjects = value.Select(t => t.GetGridObject()).ToList();

Of course, this could need a little bit more of error checking but basically, this MySuperObject is used to use any number of integers you desire, while providing you with a helper method of "GetGridObject" to fill you grid object with appropriate numbers from array of numbers.

Jure
  • 1,156
  • 5
  • 15