Spec-Zone.ru › Nim

std/parsecfg

SourceEdit

Модуль parsecfg реализует высокопроизводительный парсер конфигурационных файлов. Синтаксис конфигурационного файла аналогичен формату Windows .ini, но намного мощнее, поскольку это не построчный парсер. Строковые литералы, необработанные строковые литералы и строковые литералы в тройных кавычках поддерживаются так же, как и в языке программирования Nim.

Пример того, как может выглядеть конфигурационный файл:

# This is a comment.
; this too.

[Common]
cc=gcc     # '=' and ':' are the same
--foo="bar"   # '--cc' and 'cc' are the same, 'bar' and '"bar"' are the same (except for '#')
macrosym: "#"  # Note that '#' is interpreted as a comment without the quotation
--verbose

[Windows]
isConsoleApplication=False ; another comment

[Posix]
isConsoleApplication=True

key1: "in this string backslash escapes are interpreted\n"
key2: r"in this string not"
key3: """triple quotes strings
are also supported. They may span
multiple lines."""

--"long option with spaces": r"c:\myfiles\test.txt"

Вот пример использования парсера конфигурационных файлов:

Пример: cmd: -r:off

import std/parsecfg
import std/[strutils, streams]

let configFile = "example.ini"
var f = newFileStream(configFile, fmRead)
assert f != nil, "cannot open " & configFile
var p: CfgParser
open(p, f, configFile)
while true:
  var e = next(p)
  case e.kind
  of cfgEof: break
  of cfgSectionStart:   ## a `[section]` has been parsed
    echo "new section: " & e.section
  of cfgKeyValuePair:
    echo "key-value-pair: " & e.key & ": " & e.value
  of cfgOption:
    echo "command: " & e.key & ": " & e.value
  of cfgError:
    echo e.msg
close(p)

Пример конфигурационного файла

charset = "utf-8"
[Package]
name = "hello"
--threads:on
[Author]
name = "nim-lang"
website = "nim-lang.org"

Создание конфигурационного файла

Пример:

import std/parsecfg
var dict = newConfig()
dict.setSectionKey("","charset", "utf-8")
dict.setSectionKey("Package", "name", "hello")
dict.setSectionKey("Package", "--threads", "on")
dict.setSectionKey("Author", "name", "nim-lang")
dict.setSectionKey("Author", "website", "nim-lang.org")
assert $dict == """
charset=utf-8
[Package]
name=hello
--threads:on
[Author]
name=nim-lang
website=nim-lang.org
"""

Чтение конфигурационного файла

Пример: cmd: -r:off

import std/parsecfg
let dict = loadConfig("config.ini")
let charset = dict.getSectionValue("","charset")
let threads = dict.getSectionValue("Package","--threads")
let pname = dict.getSectionValue("Package","name")
let name = dict.getSectionValue("Author","name")
let website = dict.getSectionValue("Author","website")
echo pname & "\n" & name & "\n" & website

Изменение конфигурационного файла

Пример: cmd: -r:off

import std/parsecfg
var dict = loadConfig("config.ini")
dict.setSectionKey("Author", "name", "nim-lang")
dict.writeConfig("config.ini")

Удаление ключа раздела в конфигурационном файле

Пример: cmd: -r:off

import std/parsecfg
var dict = loadConfig("config.ini")
dict.delSectionKey("Author", "website")
dict.writeConfig("config.ini")

Поддерживаемая структура INI-файла

Пример:

import std/parsecfg
import std/streams

var dict = loadConfig(newStringStream("""[Simple Values]
    key=value
    spaces in keys=allowed
    spaces in values=allowed as well
    spaces around the delimiter = obviously
    you can also use : to delimit keys from values
    [All Values Are Strings]
    values like this: 19990429
    or this: 3.14159265359
    are they treated as numbers : no
    integers floats and booleans are held as: strings
    can use the API to get converted values directly: true
    [No Values]
    key_without_value
    # empty string value is not allowed =
    [ Seletion A   ]
    space around section name will be ignored
    [You can use comments]
    # like this
    ; or this
    # By default only in an empty line.
    # Inline comments can be harmful because they prevent users
    # from using the delimiting characters as parts of values.
    # That being said, this can be customized.
        [Sections Can Be Indented]
            can_values_be_as_well = True
            does_that_mean_anything_special = False
            purpose = formatting for readability
            # Did I mention we can indent comments, too?
    """)
)

let section1 = "Simple Values"
assert dict.getSectionValue(section1, "key") == "value"
assert dict.getSectionValue(section1, "spaces in keys") == "allowed"
assert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
assert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
assert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"

let section2 = "All Values Are Strings"
assert dict.getSectionValue(section2, "values like this") == "19990429"
assert dict.getSectionValue(section2, "or this") == "3.14159265359"
assert dict.getSectionValue(section2, "are they treated as numbers") == "no"
assert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
assert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"

let section3 = "Seletion A"
assert dict.getSectionValue(section3, 
  "space around section name will be ignored", "not an empty value") == ""

let section4 = "Sections Can Be Indented"
assert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
assert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
assert dict.getSectionValue(section4, "purpose") == "formatting for readability"

Импорты

strutils, lexbase, streams, tables, decode_helpers, since

Типы

CfgEvent = object of RootObj
  case kind*: CfgEventKind   ## the kind of the event
  of cfgEof:
    nil
  of cfgSectionStart:
    section*: string         ## `section` contains the name of the
                             ## parsed section start (syntax: `[section]`)
  of cfgKeyValuePair, cfgOption:
    key*, value*: string     ## contains the (key, value) pair if an option
                             ## of the form `--key: value` or an ordinary
                             ## `key= value` pair has been parsed.
                             ## `value==""` if it was not specified in the
                             ## configuration file.
  of cfgError:              ## the parser encountered an error: `msg`
    msg*: string             ## contains the error message. No exceptions
                             ## are thrown if a parse error occurs.
описывает событие анализа Source Edit
CfgEventKind = enum
  cfgEof,                   ## end of file reached
  cfgSectionStart,          ## a `[section]` has been parsed
  cfgKeyValuePair,          ## a `key=value` pair has been detected
  cfgOption,                ## a `--key=value` command line option
  cfgError                   ## an error occurred during parsing
перечисление всех событий, которые могут произойти при разборе Source Edit
CfgParser = object of BaseLexer
объект парсера. Source Edit
Config = OrderedTableRef[string, OrderedTableRef[string, string]]
Source Edit

Процедуры

proc `$`(dict: Config): string {....raises: [IOError, OSError],
                                 tags: [WriteIOEffect], forbids: [].}
Записывает содержимое таблицы в строку.
Примечание: Комментарии будут игнорироваться.
Source Edit
proc close(c: var CfgParser) {....gcsafe, extern: "npc$1",
                               raises: [IOError, OSError],
                               tags: [WriteIOEffect], forbids: [].}
Закрывает парсер c и связанный с ним входной поток. Source Edit
proc delSection(dict: var Config; section: string) {....raises: [], tags: [],
    forbids: [].}
Удаляет указанный раздел и все его подразделы. Source Edit
proc delSectionKey(dict: var Config; section, key: string) {....raises: [KeyError],
    tags: [], forbids: [].}
Удаляет ключ указанного раздела. Source Edit
proc errorStr(c: CfgParser; msg: string): string {....gcsafe, extern: "npc$1",
    raises: [ValueError], tags: [], forbids: [].}
Возвращает правильно отформатированное сообщение об ошибке, содержащее информацию о текущей строке и столбце. Source Edit
proc getColumn(c: CfgParser): int {....gcsafe, extern: "npc$1", raises: [],
                                    tags: [], forbids: [].}
Получает текущий столбец, к которому подошёл парсер. Source Edit
proc getFilename(c: CfgParser): string {....gcsafe, extern: "npc$1", raises: [],
    tags: [], forbids: [].}
Получает имя файла, который обрабатывает парсер. Source Edit
proc getLine(c: CfgParser): int {....gcsafe, extern: "npc$1", raises: [], tags: [],
                                  forbids: [].}
Получает текущую строку, к которой подошёл парсер. Source Edit
proc getSectionValue(dict: Config; section, key: string; defaultVal = ""): string {.
    ...raises: [KeyError], tags: [], forbids: [].}
Получает значение ключа указанного раздела. Возвращает указанное значение по умолчанию, если указанный ключ не существует. Source Edit
proc ignoreMsg(c: CfgParser; e: CfgEvent): string {....gcsafe, extern: "npc$1",
    raises: [ValueError], tags: [], forbids: [].}
Возвращает правильно отформатированное предупреждающее сообщение о том, что запись игнорируется. Source Edit
proc loadConfig(filename: string): Config {.
    ...raises: [IOError, OSError, Exception, ValueError, KeyError],
    tags: [WriteIOEffect, ReadIOEffect, RootEffect], forbids: [].}
Загружает указанный конфигурационный файл в новый экземпляр Config. Source Edit
proc loadConfig(stream: Stream; filename: string = "[stream]"): Config {.
    ...raises: [IOError, OSError, Exception, ValueError, KeyError],
    tags: [ReadIOEffect, RootEffect, WriteIOEffect], forbids: [].}
Загружает указанную конфигурацию из потока в новый экземпляр Config. Параметр filename используется только для более удобных сообщений об ошибках. Source Edit
proc newConfig(): Config {....raises: [], tags: [], forbids: [].}
Создаёт новую таблицу конфигурации. Полезно, когда нужно создать конфигурационный файл. Source Edit
proc next(c: var CfgParser): CfgEvent {....gcsafe, extern: "npc$1",
                                        raises: [IOError, OSError, ValueError],
                                        tags: [ReadIOEffect], forbids: [].}
Извлекает первое/следующее событие. Управляет парсером. Source Edit
proc open(c: var CfgParser; input: Stream; filename: string; lineOffset = 0) {.
    ...gcsafe, extern: "npc$1", raises: [IOError, OSError, Exception],
    tags: [ReadIOEffect, RootEffect], forbids: [].}
Инициализирует парсер входным потоком. Filename используется только для удобных сообщений об ошибках. lineOffset можно использовать для влияния на информацию о номере строки в генерируемых сообщениях об ошибках. Source Edit
proc setSectionKey(dict: var Config; section, key, value: string) {.
    ...raises: [KeyError], tags: [], forbids: [].}
Устанавливает значение ключа указанного раздела. Source Edit
proc warningStr(c: CfgParser; msg: string): string {....gcsafe, extern: "npc$1",
    raises: [ValueError], tags: [], forbids: [].}
Возвращает правильно отформатированное предупреждающее сообщение, содержащее информацию о текущей строке и столбце. Source Edit
proc writeConfig(dict: Config; filename: string) {....raises: [IOError, OSError],
    tags: [WriteIOEffect], forbids: [].}
Записывает содержимое таблицы в указанный конфигурационный файл.
Примечание: Комментарии будут игнорироваться.
Source Edit
proc writeConfig(dict: Config; stream: Stream) {....raises: [IOError, OSError],
    tags: [WriteIOEffect], forbids: [].}
Записывает содержимое таблицы в указанный поток.
Примечание: Комментарии будут игнорироваться.
Source Edit

Итераторы

END_OF_DOCUMENT_MARKER
iterator sections(dict: Config): lent string {....raises: [], tags: [], forbids: [].}
Перебирает секции в dict. Исходный код Редактировать

© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/parsecfg.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API