Пишу, по большей части, про историю, свою жизнь и немного про программирование.

«Go»: чтение ini-файлов

Мне тут для программы на языке «Go» понадобился простой парсер ini-файлов, который я и написал. Делюсь.

Кстати говоря, я сильно облегчил себе жизнь, когда написал небольшой bash-скрипт, компилирующий и запускающий программы на «Go», вот он:

#!/bin/bash
NAME=$1

if [ -f "$NAME" ]; then
    TMPNAME=`mktemp -t go.XXXXXXX`

    shift
    6g -I. -o $TMPNAME.6 $NAME && 6l -L. -o $TMPNAME $TMPNAME.6 && $TMPNAME $*
    rm -f $TMPNAME.6 $TMPNAME >/dev/null 2>&1
else
    echo "Error: '$NAME' is not found."
fi

Сам модуль выглядит вот так (и называется «ini»):

package ini

import (
    "os"
    "bufio"
    "strings"
)

type inisection map[string]string
type inifile map[string]inisection

func ParseFile(name string) inifile {
    f, err := os.OpenFile(name, os.O_RDONLY, 0666)
    if err != nil {
        return nil
    }

    defer f.Close()

    r := bufio.NewReader(f)

    one := inisection{}             // одна, текущая секция
    ini := inifile   {}             // все секции
    section := ""                   // текущее название секции

    for {
        line, err := r.ReadString('\n')

        if err != nil {
            break
        }

        chunks := strings.Split(strings.TrimRight(line, "\r\n"), "=", 3)
        if len(chunks) == 2 {
            key, value := strings.Trim(chunks[0], "\t "), strings.Trim(chunks[1], "\t ")

            last := len(value) - 1
            if last > 0 && value[0] == '"' && value[last] == '"' {
                value = string(value[1:last])
            }

            one[key] = string(value)
        } else {
            last := len(chunks[0]) - 1

            if chunks[0][0] == '[' && chunks[0][last] == ']' {
                ini[section] = one
                one = inisection{}
                section = string(chunks[0][1:last])
            }
        }
    }

    // «поджимаем хвост», поскольку предыдущая секция попадает в map
    // только когда появляется следующая, последнюю нужно перекладывать «руками»

    if len(one) > 0 {
        ini[section] = one
    }

    return ini
}

Модули пишутся очень просто — достаточно объявить как он будет называться (в директиве «package») и можно его подключать через «import». В «Go» модуль экспортирует всё, что начинается с большой буквы.

Мой модуль экспортирует единственную функцию — ParseFile, принимающую на вход имя файла, на выходе будет ассоциативный массив ассоциативных массивов (map of maps), ключами верхнего уровня является имя секции (если отсутствует, то имя пустое), ключами второго уровня — ключи ini-файла.

11 комментариев
bealex (bealex.livejournal.com) 2011

Не в качестве придирки, просто любопытно. Почему map — хеш? Вроде бы есть ассоциативный массив, есть прямые переводы (карта, словарь), которые зависят от языка. Ну, и вообще, map далеко не всегда внутри — основан на хеше. Или это просто привычка? А тогда откуда?

Евгений Степанищев (bolknote.ru) 2011

Комментарий для bealex.livejournal.com:

Привычка, ага. Да чёрт её знает откуда, как-то прилипла, теперь вторая натура.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для bealex.livejournal.com:

Поправил.

bealex (bealex.livejournal.com) 2011

Комментарий для Евгения Степанищева:

Выглядит хоть и правильно, но страшновато :) Кстати, чего-нить покороче «ассоциативного массива» не знаешь? Корректного, чтобы, например, на презентации можно было употреблять, но не такого длинного.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для bealex.livejournal.com:

Вообще, я думал, что не знаю, пока не вспомнил, что в Пайтоне ассоциативный массив называется «словарь».

И я вспомнил почему меня всё тянет назвать ассоциативный массив хешем. Из-за Перла, я на нём много когда-то программировал, а там ассоциативный массив называется хеш.

Евгений Степанищев (bolknote.ru) 2011

Пока писал программу, обновил версию компилятора, оказалось, что сменился вызов — вместо os.Open теперь os.OpenFile, исправил в программе.

rodem 2011

Комментарий для Евгения Степанищева:

Ну вот и Go for App Engine.
http://blog.golang.org/2011/05/go-and-google-app-engine.html

Евгений Степанищев (bolknote.ru) 2011

Комментарий для rodem:

Интересно как часто там будет компилятор меняться.

rodem 2011

Комментарий для rodem:

Пока оно всё в стадии экспериментал, то думаю что часто, раз недель в шесть.
Но лучше узнать в гугл групсах.
А вообще интересно вырастет ли из Голанга конкурент Яве для хайлоад сервер-сайд.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для rodem:

Пока оно всё в стадии эксперимента, то думаю что часто, раз недель в шесть.

Значит программы придётся проверять достаточно часто.

А вообще интересно вырастет ли из Голанга конкурент Яве для хайлоад сервер-сайд.

На Гоу сильно сложнее писать, чем на Яве.

Andrey Martemyanov 2021

в разделе секций забыл проверку на пустую строку
if chunks[0][0] == ’[’ && chunks[0][last] == ’]’ {

if len(chunks[0]) — 1 > 0 && chunks[0][0] == ’[’ && chunks[0][last] == ’]’ {

Евгений Степанищев 2021

Да, наверное, но спустя 10 лет вряд ли кому-то этот исходник нужен :)