解析配置文件C#

时间:2014-10-08 21:28:11

标签: c# parsing

我需要一些帮助来解析包含多个部分的文本文件。该文件采用以下格式:

;This is a comment that should be ignored when parsing 

;Colors in 24-bit format
#define BLUE 16711680
#define RED 255

[SETTINGS]
File Name
File Description
v1.0

[SECTION]
BLUE  N033.56.09.699 W118.25.09.714

[SECTION2]
RED    N033.56.13.675 W118.24.30.908
       N033.56.13.675 W118.24.30.908
       N033.56.16.034 W118.24.07.905

基本上,我需要跳过任何评论。我还需要能够从#define部分中提取子值。最后,我需要解析每个标题部分下的每一行(例如[SETTINGS][SECTION]等)。该文件不仅限于这些标题。

这就是我现在所拥有的,但它显然不起作用。

string line;
while ((line = reader.ReadLine()) != null)
{
    string[] items = line.Split('\t');
    foreach (string item in items)
    {
        if(item.StartsWith("[SETTINGS]"))
        {

        }
        if(item.StartsWith("[SECTIOn]"))
        {

        }
    }
}

3 个答案:

答案 0 :(得分:3)

如果这是您想要的数据结构类型,您可以使用以下代码....

This is what the result will pretty much look like

void Main()
{
    // Gets rid of any comments that exist in our config file
    IEnumerable<string> textLines = text.Split('\n')
                                        .Where(line => !line.StartsWith(";"));;

    // Converts our 'IEnumerable<string> textLines' back to a string without comments
    string textWithoutComments = string.Join("\n", textLines);

    // Retrieves which variables are defined
    // >> BLUE 16711680 
    // >> RED 255 
    Dictionary<string, string> definedVariables = textLines .Where(line => line.StartsWith(@"#define"))
                                                            .Select(line => Regex.Match(line, @"#define ([^ ]*) (.*)"))
                                                            .ToDictionary(match => match.Groups[1].Value, match => match.Groups[2].Value);

    // Creates a dictionary of sections that have been defined
    // >> SETTINGS      File Name
    // >>               File Description
    // >>               v1.0
    // >>
    // >> SECTION BLUE  N033.56.09.699 W118.25.09.714
    // >>
    // >> SECTION2 RED  N033.56.13.675 W118.24.30.908
    // >>               N033.56.13.675 W118.24.30.908
    // >>               N033.56.16.034 W118.24.07.905 
    Dictionary<string, string> sectionDictionary = Regex.Matches(textWithoutComments, @"\[([\w]*)\]\n([^\[^\#]*)")
                                                        .Cast<Match>()
                                                        .ToDictionary(match => match.Groups[1].Value, match => match.Groups[2].Value);


    UserConfiguration userConfig = new UserConfiguration 
    {
        Variables = definedVariables,
        Settings  = sectionDictionary["SETTINGS"],
        Sections  = sectionDictionary.Where(dictionary  => dictionary.Key != "SETTINGS")
                                    .Select(dictionary  => new {Key = dictionary.Key, Value = Regex.Match(dictionary.Value, @"(\w*) ([^\[]*)")})
                                    .ToDictionary(anon => anon.Key, anon => new Config 
                                    { 
                                        Name = anon.Value.Groups[1].Value, 
                                        Value = anon.Value.Groups[2].Value.RemoveWhiteSpace()
                                    })
    };

}
public class UserConfiguration
{
    public Dictionary<string, string> Variables { get; set; }
    public string Settings { get; set; }
    public Dictionary<string, Config> Sections { get; set; }
}

public class Config
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public static class Extensions
{
    public static string RemoveWhiteSpace(this string text)
    {
        var lines = text.Split('\n');
        return string.Join("\n", lines.Select(str => str.Trim()));
    }
}

const string text = @";This is a comment that should be ignored when parsing 

;Colors in 24-bit format
#define BLUE 16711680
#define RED 255

[SETTINGS]
File Name
File Description
v1.0

[SECTION]
BLUE  N033.56.09.699 W118.25.09.714

[SECTION2]
RED    N033.56.13.675 W118.24.30.908
    N033.56.13.675 W118.24.30.908
    N033.56.16.034 W118.24.07.905";

答案 1 :(得分:0)

不想测试它,但这是一个开始:

string line;
Dictionary Define<string, int> = new Dictionary<string, int>();

while ((line = reader.ReadLine()) != null)
{
   if(line.StartsWith(";"))
   {
      continue;
   }

   if(line.StartsWith("#define")
   {
      string[] defineItems = line.Split();
      Define[defineItems[1]] = defineItems[2];
      continue;
   }

   if(line.StartsWith("[SETTINGS]"))
        {

        }
        if(item.StartsWith("[SECTIOn]"))
        {

        }

}

答案 2 :(得分:0)

我在字典中创建了不同的操作以允许可读性 - 当您开始添加部分时,if语句将变成可维护性的噩梦。我使用控制台进行了测试,所以这在代码方面有点粗糙。简而言之:

查看记录是否为#definition记录,如果是,则将其拆分为名称和值字符串集。

如果记录是代码注释记录,请跳过。

如果记录以字典键中的任何内容开头,请将当前部分更新为该字段。因此,当您看到[Settings]时,当前操作将为UpdateSettingsConfiguration,当您看到[Section]时,当前操作将为UpdateSectionConfiguration

当记录不是注释,#definition记录或节标题时,它将调用应用于最近定义的节标题的Action并允许其处理。如果用户顽皮并在文件中的多个位置定义[Settings],这也很方便。

class Program {
    private const string ConfigComment = ";";
    private const string ConfigDefine = "#define";
    private static readonly KeyValuePair<string, Action<string>> DefaultActionValuePair = new KeyValuePair<string, Action<string>>();
    private static readonly Dictionary<string, Action<string>> settingSection = new Dictionary<string, Action<string>>(){
            { "[SETTINGS]", UpdateSettingsConfiguration}
            { "[Section]", UpdateSectionConfiguration}
        };
    static void Main() {

        StreamReader reader = new StreamReader("input.txt");
        string currentLine = reader.ReadLine();
        Action<string> currentSection = null;
        do {
            if (currentLine.StartsWith(ConfigDefine)) { //Definitions are used different than the rest of the config file, handle them special.
                string[] definition = currentLine.Substring(ConfigDefine.Length + 1).Split(' ');

                AddDefinitions(definition[0], definition[1]);
            } else if (!currentLine.StartsWith(ConfigComment)) {

                var kvp =
                    settingSection.FirstOrDefault(
                        x => x.Key.StartsWith(currentLine, StringComparison.InvariantCultureIgnoreCase));
                if (kvp.Equals(DefaultActionValuePair)) {


                    if (currentSection == null) {
                        //Invalid setting
                    } else {
                        currentSection(currentLine);
                    }
                } else {
                    currentSection = kvp.Value;
                }
            }
            currentLine = reader.ReadLine();

        } while (!reader.EndOfStream);
    }

    private static void AddDefinitions(string p1, string p2) {
        //Do stuff here
    }

    static void UpdateSettingsConfiguration(string setting) {
        //do stuff here
    }
    static void UpdateSectionConfiguration(string setting) {
        //do stuff here
    }
}