public static bool Parse(string data, out string errorMessage, out IList <Tag> tags) { errorMessage = null; tags = null; Match m = null; Group mg = null; int i = 0, l = 0, index = 0; var t = (Factory.TagOption)null; var line = string.Empty; var parserItem = (ParserItem)null; var parserItems = new List <ParserItem>(); var rawLines = DataBlock(data); for (i = 0, l = rawLines.Length; i < l; i++) { line = rawLines[i]; if (line.StartsWith(":")) { m = label.Match(line); if (m.Success) { t = Factory.Tag(m.Groups[1].Value, m.Groups[2].Value); if (null == t) { errorMessage = string.Format("Unknown field {0}{1}.", m.Groups[1].Value, m.Groups[2].Value); return(false); } else { parserItem = new ParserItem { TagOption = t, Tag = new Field(m.Groups[1].Value, m.Groups[2].Value, index) }; ++index; parserItems.Add(parserItem); line = m.Groups[3].Value; } } else { errorMessage = string.Format("Invalid field definition at line {0}.", i + 1); return(false); } } if (null == parserItem || parserItem.TagOption.MultiLine == parserItem.Lines) { errorMessage = string.Format("Expect field definition at the line {0}.", i + 1); return(false); } else { parserItem.Append(line); } } foreach (var item in parserItems) { var lineIndex = 0; NameMap map = null; var lines = item.Lines; var options = item.TagOption; var tag = item.Tag; TagValue grouping; TagValue previous; tag.Raw = item.Data; // item.TagOption.CounterPostfix remove this at some poit and support SubTag field which can combine multiple values againts one key if (options.Blob) { tag.Value = item.Data; continue; } else { grouping = null; previous = null; foreach (var r in options.Rows) { map = null; if (r.ValueNames != null && r.ValueNames[0].StartsWith("$")) { map = DecodeNames(r.ValueNames[0]); } i = 0; do { line = item[lineIndex]; for (int idx = 0, len = r.Regex.Length; idx < len; idx++) { m = r.Regex[idx].Match(line); if (m.Success) { if (map == null) { if (r.ValueNames == null || 0 == r.ValueNames.Length) { tag.Value = m.Value; } else { foreach (var id in r.ValueNames) { if ((mg = m.Groups[id]).Success) { tag.Add(id, mg.Value); } } } } else { if (map.ByIndex) { if (map.Grouping(idx)) { var groupingKey = map.GroupingKey(idx); if (map.Previous(idx)) { if (previous != null && previous.Id == groupingKey) { grouping = previous; } } else { if (grouping == null || grouping.Id != groupingKey) { grouping = tag.Add(groupingKey); } } } foreach (var id in map.GetOthers(idx)) { if ((mg = m.Groups[id]).Success) { if (null == grouping) { tag.Add(id, mg.Value); } else { grouping.Add(id, mg.Value); } } } previous = grouping; grouping = null; } else { item.Tag.Add( map.GetId(m), map.GetValue(m)); foreach (var id in map.GetOthers(m)) { if ((mg = m.Groups[id]).Success) { tag.Add(id, mg.Value); } } } } break; } } if (!m.Success && !r.Optional) { errorMessage = string.Format("Field {0} isn't optional.", item.Tag.Id); return(false); } if (m.Success) { ++lineIndex; ++i; } }while (i < r.Lines && lineIndex < lines && m.Success); if (lineIndex >= lines) // no more data if regex exists we need to skep them { break; } } } if (lineIndex < lines) { errorMessage = string.Format("Field {0} can't match data.", item.Tag.Id); return(false); } } tags = parserItems .Select(item => item.Tag) .Cast <Tag>() .ToList(); return(true); }