2

我有一个看起来像的文本文件

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

4 回答 4

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;} }
}
于 2012-12-21T04:21:10.647 回答
1

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

在您的示例中,您列出了:

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

这两条线相互矛盾。settings.settings5 将使键 settings5 在字典中存储一个值,但下一行期望 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. 您会发现它确实填充了您的对象。从中检索值很痛苦。因为您必须将每个结果转换为字符串或另一个字典。

无论哪种方式,您都会发现您很可能希望避免为此目的创建字典字典。

于 2012-12-21T04:24:49.667 回答
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=""******""
";
于 2012-12-21T04:29:11.980 回答
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);
            }
        }
    }
}

感谢大家在这方面的帮助!

于 2012-12-21T04:39:13.483 回答