Thursday, June 02, 2016

Parsing INI files

I am trying to allow the end user to modify the application behavior in some limited ways; as such, I have a need of parsing .INI files of the form

[Type 1]
contains=abc
contains=def

[Type 2]
contains=1234

I looked around for a class / library that would allow me to read these files but I haven't found anything useful (most of the classes I found couldn't handle duplicate keys within the same section). As such, I went ahead and implemented this myself. This algorithm is extremely specific to my usage, you might have to modify it for your needs.

The IniTuple represents each line as a (section, key, value) tuple:

    public class IniTuple
    {
        public string Section { get; private set; }
        public string Key { get; private set; }
        public string Value { get; private set; }

        public IniTuple(string section, string key, string value)
        {
            Section = section;
            Key = key;
            Value = value;
        }
    }

The IniParser class implements the algorithm that transforms a string to a list of IniTuples:

    public class IniParser
    {
        public IEnumerable<IniTuple> Read(string text)
        {
            var lines = text
                .Split('\r', '\n')
                .Select(RemoveComment)
                .Where(line => !string.IsNullOrWhiteSpace(line))
                .ToArray();

            var section = "";
            foreach (var line in lines)
            {
                if (IsNewSection(line))
                    section = line.Substring(1, line.Length - 2);
                else
                    yield return GetTuple(section, line);
            }
        }

        //

        private static string RemoveComment(string line)
        {
            var index = line.IndexOf(';');
            return index < 0 ? line : line.Substring(0, index);
        }

        private static bool IsNewSection(string line)
        {
            return Regex.IsMatch(line, @"^\s*\[[^]]+\]\s*$");
        }

        private static IniTuple GetTuple(string section, string line)
        {
            var index = line.IndexOf('=');
            return index < 0
                ? new IniTuple(section, "", line)
                : new IniTuple(section, line.Substring(0, index), line.Substring(index + 1));
        }
    }

Please let me know if this was useful. As usual, I don't believe in copyrights so feel free to do whatever you want with the code.

No comments: