Solution: Parse ini file



examples/parse-ini/parse_ini.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "regexp"
)

func main() {

}

func parseIni(filename string) (map[string]map[string]string, error) {
    ini := make(map[string]map[string]string)
    var head string

    fh, err := os.Open(filename)
    if err != nil {
        return ini, fmt.Errorf("Could not open file '%v': %v", filename, err)
    }
    sectionHead := regexp.MustCompile(`^\[([^]]*)\]\s*$`)
    keyValue := regexp.MustCompile(`^(\w*)\s*=\s*(.*?)\s*$`)
    reader := bufio.NewReader(fh)
    for {
        line, _ := reader.ReadString('\n')
        //fmt.Print(line)
        result := sectionHead.FindStringSubmatch(line)
        if len(result) > 0 {
            head = result[1]
            //fmt.Printf("found: %s\n", head)
            ini[head] = make(map[string]string)
            continue
        }

        result = keyValue.FindStringSubmatch(line)
        if len(result) > 0 {
            key, value := result[1], result[2]
            //fmt.Printf("kv: '%q'\n", result)
            ini[head][key] = value
            continue
        }

        if line == "" {
            break
        }
    }

    //ini["foo"] = "bar"

    return ini, nil
}

examples/parse-ini/parse_ini_test.go
package main

import (
    "fmt"
    "testing"
)

func TestParseIni(t *testing.T) {
    actual, err := parseIni("data.ini")
    if err != nil {
        t.Error(fmt.Sprintf("Error in parsing: '%v'", err))
    }
    expected := make(map[string]map[string]string)
    expected["first section"] = make(map[string]string)
    expected["first section"]["a"] = "23"
    expected["first section"]["b"] = "12"
    expected["second section"] = make(map[string]string)
    expected["second section"]["a"] = "42"
    if !compareMapMap(actual, expected) {
        t.Error(fmt.Sprintf("Expected '%v', Actual '%v'", expected, actual))
    }
}

func compareMapMap(a, b map[string]map[string]string) bool {
    //fmt.Println(a)
    //fmt.Println(b)
    if len(a) != len(b) {
        return false
    }
    for key, value := range a {
        if !compareMap(value, b[key]) {
            return false
        }
    }
    for key, value := range b {
        if !compareMap(value, a[key]) {
            return false
        }
    }
    return true
}

func compareMap(a, b map[string]string) bool {
    //fmt.Println(a)
    //fmt.Println(b)
    if len(a) != len(b) {
        return false
    }
    for key, value := range a {
        if value != b[key] {
            return false
        }
    }
    for key, value := range b {
        if value != a[key] {
            return false
        }
    }
    return true
}