Is there a good C# design pattern for parsing strings that when split have different amounts of data?-Collection of common programming errors
-
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 what you’re looking for:
class ItemDesc { public string Ident { get; private set; } public string Fields { get; private set; } public ItemDesc(string id, string flds) { Ident = id; Fields = flds; } }
The
Fields
property is just a string that contains one-character type descriptions for the variable data. That is, “isss” would be interpreted asint,string,string,string
.You can then build a
Dictionary
that you can use to look these up:Dictionary ItemLookup = new Dictionary { { "ItemType1", new ItemDesc("ItemType1", "isss") }, { "ItemType2", new ItemDesc("ItemType2", "iisss") }, };
Now when you read a line, use
string.Split()
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:string line = GetLine(); var fields = line.Split(','); // somehow get the identifier string id = GetIdentifier(); ItemDesc desc; if (!ItemLookup.TryGetValue(id, out desc)) { // unrecognized identifier } else { int fieldNo = 3; // or whatever field is after the identifier foreach (var c in desc.Fields) { switch (c) { case 'i' : // try to parse an int and save it. break; case 's' : // save the string break; default: // error, unknown field type break; } ++fieldNo; } } // at this point if no errors occurred, then you have a collection // of parsed fields that you saved. You can now create your object.
-
Just split them using
string.Split()
, and thenint.Parse()
orint.TryParse()
eachint
value in the resulting array as needed.var myStrings = string.Split(sourceString); int myint1 = int.Parse(myStrings[0]);
-
There are several ways of dealing with this. Here’s a simple one (outputting just an object array):
class Template { // map identifiers to templates static Dictionary templates = new Dictionary { { "type1", "isss" }, { "type2", "iisss" }, }; static bool ParseItem(string input, char type, out object output) { output = null; switch (type) { case 'i': int i; bool valid = int.TryParse(input, out i); output = i; return valid; case 's': output = input; return true; } return false; } public static object[] ParseString(string input) { string[] items = input.Split(','); // make sure we have enough items if (items.Length < 2) return null; object[] output = new object[items.Length - 2]; string identifier = items[1]; string template; // make sure a valid identifier was specified if (!templates.TryGetValue(identifier, out template)) return null; // make sure we have the right amount of data if (template.Length != output.Length) return null; // parse each item for (int i = 0; i < template.Length; i++) if (!ParseItem(items[i + 2], template[i], out output[i])) return null; return output; } }
-
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.
- Interpreter
- Strategy
- Builder
Originally posted 2013-11-09 19:43:58.