Динамическая структура для хранения типизированных данных - C#
Формулировка задачи:
Дано:
ini-файл со следующей структурой
раздел 1
список таблиц таблица 1 ... таблица j
таблица 1 ключ_1,значение_1 ключ_1,значение_1
... ... ...
таблица n ключ_m,значение_m ключ_l,значение_l
...
раздел k
список таблиц таблица 1 ...
таблица 1 ключ_1,значение_1
... ...
таблица j ключ_i,значение_i
по сути это схема репликации баз данных: раздел это одна база данных с таблицами обозначенными в списке таблиц, а ключ,значение описание имен и типов столбцов.
Имена таблиц в различных разделах могут совпадать, ключи в различных таблицах могут совпадать
В зависимости от подписки на получаемую информацию может изменяться количество разделов и количество таблиц в них.
Программа не должна заранее знать ничего о названиях разделов, таблиц и т.д.
Вопрос: Как считать эти данные из файла понятно, но в какую структуру и как сохранять?
Вопрос: Как с
Поскольку движок автоматически удаляет "лишние" пробелы, повторю несколько в другом виде:
Дано:
ini-файл со следующей структурой
[раздел: name1]
;список таблиц
table=table_1
...
table=table_n
[table:name1:table_1]
field=key_1,value_1
...
field=key_j,value_j
[раздел: nameN]
;список таблиц
table=table_1
...
table=table_m
[table:nameN:table_1]
field=key_1,value_1
...
field=key_l,value_l
по сути это схема репликации баз данных: раздел это одна база данных с таблицами обозначенными в списке таблиц, а ключ,значение описание имен и типов столбцов.
Имена таблиц в различных разделах могут совпадать, ключи в различных таблицах могут совпадать
В зависимости от подписки на получаемую информацию может изменяться количество разделов и количество таблиц в них.
Программа не должна заранее знать ничего о названиях разделов, таблиц и т.д.
Вопрос: Как считать эти данные из файла понятно, но в какую структуру и как сохранять?
Решение задачи: «Динамическая структура для хранения типизированных данных»
textual
Листинг программы
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication
{
internal class Program
{
private static void Main()
{
var parser = new Parser(@"D:\forts_scheme.ini.txt", Encoding.ASCII);
var timer = new Stopwatch();
timer.Start();
var data = parser.Parsing();
timer.Stop();
Console.WriteLine("Time of parsing: {0} ms", timer.ElapsedMilliseconds);
Console.WriteLine("Test:");
foreach (var scheme in data)
{
Console.WriteLine("Scheme: {0}", scheme.Key);
foreach (var table in scheme.Value)
Console.WriteLine("The table {0} has {1} fields", table.Key, table.Value.Count());
}
Console.WriteLine("Example of first field:");
var firstScheme = data.First();
var firstTable = firstScheme.Value.First();
var firstField = firstTable.Value.First();
Console.WriteLine("{0} -> {1} -> {2} = {3}", firstScheme.Key, firstTable.Key, firstField.Key, firstField.Value);
}
}
public class Parser
{
private static readonly Regex schemeRegex = new Regex(@"\[dbscheme:(.+)\]", RegexOptions.Compiled);
private static readonly Regex tableRegex = new Regex(@"\[table:(.+):(.+)\]", RegexOptions.Compiled);
private static readonly Regex fieldRegex = new Regex(@"field\=(.+),(.+)", RegexOptions.Compiled);
private readonly string path;
private readonly Encoding encoding;
private Dictionary<string, Section> schemes;
private string scheme;
private string table;
public Parser(string path, Encoding encoding)
{
this.path = path;
this.encoding = encoding;
}
public Dictionary<string, Section> Parsing()
{
schemes = new Dictionary<string, Section>();
using (var reader = new StreamReader(path, encoding))
{
string line;
var entityType = EntityType.Scheme;
while ((line = reader.ReadLine()) != null)
switch (entityType)
{
case EntityType.Scheme:
if (CheckScheme(line)) entityType = EntityType.Table;
break;
case EntityType.Table:
if (CheckTable(line)) entityType = EntityType.Field;
break;
case EntityType.Field:
if (!CheckField(line) && !CheckTable(line) && CheckScheme(line))
entityType = EntityType.Table;
break;
}
}
return schemes;
}
private bool CheckScheme(string line)
{
var match = schemeRegex.Match(line);
if (match.Success)
schemes.Add(match.Groups[1].Value, new Section());
return match.Success;
}
private bool CheckTable(string line)
{
var match = tableRegex.Match(line);
if (match.Success)
{
scheme = match.Groups[1].Value;
table = match.Groups[2].Value;
schemes[scheme].AddTable(table);
}
return match.Success;
}
private bool CheckField(string line)
{
var match = fieldRegex.Match(line);
if (match.Success)
schemes[scheme].AddFieldToTable(table, match.Groups[1].Value, match.Groups[2].Value);
return match.Success;
}
private enum EntityType
{
Scheme,
Table,
Field
}
}
public class Section : IEnumerable<KeyValuePair<string, Table>>
{
private readonly Dictionary<string, Table> tables = new Dictionary<string, Table>();
public void AddTable(string name)
{
tables.Add(name, new Table());
}
public void AddFieldToTable(string name, string key, string value)
{
tables[name].AddField(key, value);
}
public Table GetTable(string name)
{
return tables[name];
}
public IEnumerator<KeyValuePair<string, Table>> GetEnumerator()
{
return ((IEnumerable<KeyValuePair<string, Table>>)tables).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Table : IEnumerable<Field>
{
private readonly Dictionary<string, string> fields = new Dictionary<string, string>();
public void AddField(string key, string value)
{
fields.Add(key, value);
}
public string GetField(string key)
{
return fields[key];
}
public IEnumerator<Field> GetEnumerator()
{
return fields.Select(field => new Field(field.Key, field.Value)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public struct Field
{
public Field(string key, string value) : this()
{
Key = key;
Value = value;
}
public string Key { get; set; }
public string Value { get; set; }
}
}