2014-10-08 3 views
2

Мне нужна помощь при разборе текстового файла, который содержит несколько разделов. Файл указан в следующем формате:Файл конфигурации анализа C#

;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]")) 
     { 

     } 
    } 
} 
+4

Не было бы проще использовать приложение. config или файл web.config с ''? Может быть, даже пользовательский раздел конфигурации? – Tim

+0

@Tim, короткий ответ: нет. Это связано с тем, что файл конфигурации, который должен быть проанализирован, импортируется конечным пользователем, поэтому могут быть разные варианты конфигурационных данных. – Nicholas

+0

Что касается переменных в разделе «#define», они несут один и тот же формат пары значений ключа, как в '#define'] [' KEY'] ['VALUE' –

ответ

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"; 
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]")) 
     { 

     } 

} 
+0

Поскольку он читается по очереди, мне любопытно, как вы ассоциируете «Имя файла» с «[НАСТРОЙКИ]» в этом примере кода. – AWinkle

0

Я сделал разделы различных действий в словаре, чтобы обеспечить читаемость - как начать добавление разделов if заявления будет просто перерасти в кошмар ремонтируемости. Я тестировал с помощью консоли, так что это немного неполированный код. Вкратце:

Посмотрите, является ли запись записью #definition, если она есть, разделите ее на строку с именем и значением.

Если запись является записью комментария кодов, пропустите.

Если запись начинается с чего-либо в клавишах словаря, обновите текущий раздел до этого. Поэтому, когда вы видите [Settings], текущее действие будет UpdateSettingsConfiguration, и когда вы увидите [Section], текущее действие будет UpdateSectionConfiguration.

Если запись не является комментарием, запись #definition или заголовок раздела, она вызывет действие, которое применяется к самому последнему определенному заголовку раздела и разрешит его обрабатывать. Это также может быть полезно в случае, если пользователи непослушны и определяют [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 
    } 
} 
Смежные вопросы