将字符串转换为多级字典

时间:2012-12-21 04:03:02

标签: c# parsing dictionary

我有一个看起来像

的文本文件
tabs.main="******"
tabs.settings="******"

settings.setting1="******"
settings.setting2="******"
settings.setting3="******"
settings.setting4="******"

settings.setting5.title="******"
settings.setting5.settingoption1="******"
settings.setting5.settingoption2="******"

我希望能够将其解析为多层次的词典。例如,我有一个类似于Dictionary<string, object>的根词典,并且我会有自己的Dictionary<string, object>选项卡和设置。以图形的形式,我想要的是:

Dictionary<string, object>
   -> Dictionary<"tabs", object>
      -> Dictionary<"main", "*******">
      -> Dictionary<"settings", "*******">
   -> Dictionary<"settings", object>
      -> Dictionary<"setting1", "*******">

依此类推。这可能吗?如果是这样,有人可以给我指向正确的方向。

4 个答案:

答案 0 :(得分:2)

字典并非真正用于以这种方式保存您的数据。您可以创建表示文件的类,并将数据加载到文件中。根据你所展示的内容,这可能有用。

public class File
{
    private List<Setting> settings = new List<Setting>();
    public Tab Tab { get; set; }
    public List<Setting> Settings { get{ return settings; } }
}

public class Tab
{
    public string Main{ get; set;}
    public string Settings{ get; set;}
}

public class Setting
{
    private List<string> options = new List<string>();
    public string Value{ get; set; }
    public List<string> Options{ get{ return options;} }
}

答案 1 :(得分:1)

您将遇到的问题是,您的某些密钥需要存储在字典中,其中包含值(可能是字符串),其中一些密钥需要与字典一起存储。

在您的示例中列出了:

settings.setting5="******"
settings.setting5.settingoption1="******"

这两条线相互矛盾。 settings.settings5将使键设置5在字典中存储一个值,但下一行是期望settings5是其他值的字典。

您可以编写一段代码:

var settings = new Dictionary<string, object>();
var lines = File.ReadAllLines("...");
foreach (var line in lines)
{
    var parts = line.Split(new char[] { '=' }, 2);
    if (parts.Length != 2) continue;

    var keys = parts[0].Split('.');
    var value = parts[1];

    var dict = settings;
    for (int i = 0; i < keys.Length - 1; i++)
    {
        if (!dict.ContainsKey(keys[i]))
            dict.Add(keys[i], new Dictionary<string, object>());
        dict = (Dictionary<string, object>)dict[keys[i]];
    }

    dict.Add(keys[keys.Length - 1], value);
}
  1. 没有任何错误检查。
  2. 你会发现它确实填充你的对象。从中检索值是一种痛苦。因为您必须将每个结果转换为字符串或其他字典。
  3. 无论哪种方式,你都会发现你很可能会为此避免尝试创建字典词典。

答案 2 :(得分:0)

请考虑使用字典以外的对象,但要回答您的问题。

请注意,此数据结构不允许字典和具有相同键的字符串值。

static Dictionary<string,object> Parse(string contents)
{
   var root = new Dictionary<string,object>();

   using (var rdr = new StringReader(contents))
   {
      string line;
      var equals = new [] {'='};
      while(null != (line = rdr.ReadLine()))
      {
         if(!string.IsNullOrEmpty(line))
         {
            var keyValue = line.Split(equals, 2);
            AddValue(root, keyValue[0], keyValue[1]);
         }
      }
   }

   return root;
}

static void AddValue(Dictionary<string,object> dict, string dottedKeys, string value)
{
   string [] keys = dottedKeys.Split('.');
   for(var i = 0; i < keys.Length - 1; i++)
   {
      var key = keys[i];
      dict = GetOrAdd(dict, key);
   }
   dict[keys[keys.Length - 1]] = value;
}

static Dictionary<string,object> GetOrAdd(Dictionary<string,object> parent, string key)
{
   object o;
   Dictionary<string,object> childDict;
   if(parent.TryGetValue(key, out o))
      childDict = (Dictionary<string,object>) o;  // This will throw when adding a dictionary to a value.
   else
      parent[key] = childDict = new Dictionary<string,object>();
   return childDict;
}

static string fileContents=@"
tabs.main=""******""
tabs.settings=""******""

settings.setting1=""******""
settings.setting2=""******""
settings.setting3=""******""
settings.setting4=""******""
settings.setting5=""******""

settings.setting6.settingoption1=""******""
settings.setting6.settingoption2=""******""
";

答案 3 :(得分:0)

我实际上最终还是设法自己修改了一些代码,但是由于我不想浪费时间来回答这个问题,我会将Jason的问题标记为答案,因为它有点像我提出的那样。他帮我写了我的代码!

Dictionary<string, object> _dic = new Dictionary<string, object>();
using(StreamReader reader = new StreamReader(file))
{
    string text;
    while ((text = reader.ReadLine()) != null)
    {
        if (text.Equals(String.Empty))
            continue;
        string line = text.Trim();
        string[] keyval = line.Split('=');
        string value = keyval[1].Trim('"');
        string[] keys = keyval[0].Split('.');
        Dictionary<string, object> prevDic = _dic;
        for (int i = 0; i < keys.Length; i++)
        {
            if (i + 1 != keys.Length)
            {
                Dictionary<string, object> temp = new Dictionary<string, object>();
                if (prevDic.ContainsKey(keys[i]))
                {
                    prevDic = prevDic[keys[i]] as Dictionary<string, object>; // Avoids exceptions when trying to cast the string value to a dictionary
                    continue;
                }
                else
                {
                    prevDic.Add(keys[i], temp);
                    prevDic = temp;
                }
            }
            else
            {
                prevDic.Add(keys[i], value);
            }
        }
    }
}

感谢大家的帮助!