{"id":464,"date":"2022-08-30T15:01:47","date_gmt":"2022-08-30T15:01:47","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/11\/09\/is-there-a-good-c-design-pattern-for-parsing-strings-that-when-split-have-different-amounts-of-data-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:01:47","modified_gmt":"2022-08-30T15:01:47","slug":"is-there-a-good-c-design-pattern-for-parsing-strings-that-when-split-have-different-amounts-of-data-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/is-there-a-good-c-design-pattern-for-parsing-strings-that-when-split-have-different-amounts-of-data-collection-of-common-programming-errors\/","title":{"rendered":"Is there a good C# design pattern for parsing strings that when split have different amounts of data?-Collection of common programming errors"},"content":{"rendered":"<ul>\n<li>\n<p>If all the lines start with <code>common data, identifier<\/code>, and then are followed by a variable but expected (i.e. known based on the identifier) set of values, then a table approach could work well. To continue your example, say you have two different types:<\/p>\n<ul>\n<li>common data,identifier,int,string,string,string.<\/li>\n<li>common data,identifier,int,int,string,string,string.<\/li>\n<\/ul>\n<p>You can build a class that defines what you&#8217;re looking for:<\/p>\n<pre><code>class ItemDesc\n{\n    public string Ident { get; private set; }\n    public string Fields { get; private set; }\n    public ItemDesc(string id, string flds)\n    {\n        Ident = id;\n        Fields = flds;\n    }\n}\n<\/code><\/pre>\n<p>The <code>Fields<\/code> property is just a string that contains one-character type descriptions for the variable data. That is, &#8220;isss&#8221; would be interpreted as <code>int,string,string,string<\/code>.<\/p>\n<p>You can then build a <code>Dictionary<\/code> that you can use to look these up:<\/p>\n<pre><code>Dictionary ItemLookup = new Dictionary\n{\n    { \"ItemType1\", new ItemDesc(\"ItemType1\", \"isss\") },\n    { \"ItemType2\", new ItemDesc(\"ItemType2\", \"iisss\") },\n};\n<\/code><\/pre>\n<p>Now when you read a line, use <code>string.Split()<\/code> to split it into fields. Get the identifier, look it up the dictionary to get the item descriptions, and then parse the rest of the fields. Something like:<\/p>\n<pre><code>string line = GetLine();\nvar fields = line.Split(',');\n\/\/ somehow get the identifier\nstring id = GetIdentifier();\nItemDesc desc;\nif (!ItemLookup.TryGetValue(id, out desc))\n{\n    \/\/ unrecognized identifier\n}\nelse\n{\n    int fieldNo = 3; \/\/ or whatever field is after the identifier\n    foreach (var c in desc.Fields)\n    {\n        switch (c)\n        {\n            case 'i' :\n               \/\/ try to parse an int and save it.\n               break;\n            case 's' :\n               \/\/ save the string\n               break;\n            default:\n               \/\/ error, unknown field type\n               break;\n         }\n         ++fieldNo;\n    }\n}\n\/\/ at this point if no errors occurred, then you have a collection\n\/\/ of parsed fields that you saved.  You can now create your object.\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Just split them using <strong><code>string.Split()<\/code><\/strong>, and then <strong><code>int.Parse()<\/code><\/strong> or <strong><code>int.TryParse()<\/code><\/strong> each <code>int<\/code> value in the resulting array as needed.<\/p>\n<pre><code>var myStrings = string.Split(sourceString);\nint myint1 = int.Parse(myStrings[0]);\n<\/code><\/pre>\n<\/li>\n<li>\n<p>There are several ways of dealing with this. Here&#8217;s a simple one (outputting just an object array):<\/p>\n<pre><code>class Template\n{\n    \/\/ map identifiers to templates\n    static Dictionary templates = new Dictionary\n    {\n        { \"type1\", \"isss\" },\n        { \"type2\", \"iisss\" },\n    };\n\n    static bool ParseItem(string input, char type, out object output)\n    {\n        output = null;\n        switch (type)\n        {\n            case 'i':\n                int i;\n                bool valid = int.TryParse(input, out i);\n                output = i;\n                return valid;\n            case 's':\n                output = input;\n                return true;\n        }\n        return false;\n    }\n\n    public static object[] ParseString(string input)\n    {\n        string[] items = input.Split(',');\n        \/\/ make sure we have enough items\n        if (items.Length &lt; 2)\n            return null;\n        object[] output = new object[items.Length - 2];\n        string identifier = items[1];\n        string template;\n        \/\/ make sure a valid identifier was specified\n        if (!templates.TryGetValue(identifier, out template))\n            return null;\n        \/\/ make sure we have the right amount of data\n        if (template.Length != output.Length)\n            return null;\n        \/\/ parse each item\n        for (int i = 0; i &lt; template.Length; i++)\n            if (!ParseItem(items[i + 2], template[i], out output[i]))\n                return null;\n        return output;\n    }\n}\n<\/code><\/pre>\n<\/li>\n<li>\n<p>would need little more details, based on your problem domain it could entirely change. but following seem to be the first set of patterns, they are ordered on suitability.<\/p>\n<ul>\n<li>Interpreter<\/li>\n<li>Strategy<\/li>\n<li>Builder<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p id=\"rop\"><small>Originally posted 2013-11-09 19:43:58. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>If all the lines start with common data, identifier, and then are followed by a variable but expected (i.e. known based on the identifier) set of values, then a table approach could work well. To continue your example, say you have two different types: common data,identifier,int,string,string,string. common data,identifier,int,int,string,string,string. You can build a class that defines [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-464","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/464","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=464"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/464\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}