Working with values

To get a string value:

  1. val := cfg.Section("").Key("key name").String()

To validate key value on the fly:

  1. val := cfg.Section("").Key("key name").Validate(func(in string) string {
  2. if len(in) == 0 {
  3. return "default"
  4. }
  5. return in
  6. })

If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance):

  1. val := cfg.Section("").Key("key name").Value()

To check if raw value exists:

  1. yes := cfg.Section("").HasValue("test value")

To get value with types:

  1. // For boolean values:
  2. // true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On
  3. // false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off
  4. v, err = cfg.Section("").Key("BOOL").Bool()
  5. v, err = cfg.Section("").Key("FLOAT64").Float64()
  6. v, err = cfg.Section("").Key("INT").Int()
  7. v, err = cfg.Section("").Key("INT64").Int64()
  8. v, err = cfg.Section("").Key("UINT").Uint()
  9. v, err = cfg.Section("").Key("UINT64").Uint64()
  10. v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
  11. v, err = cfg.Section("").Key("TIME").Time() // RFC3339
  12. v = cfg.Section("").Key("BOOL").MustBool()
  13. v = cfg.Section("").Key("FLOAT64").MustFloat64()
  14. v = cfg.Section("").Key("INT").MustInt()
  15. v = cfg.Section("").Key("INT64").MustInt64()
  16. v = cfg.Section("").Key("UINT").MustUint()
  17. v = cfg.Section("").Key("UINT64").MustUint64()
  18. v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
  19. v = cfg.Section("").Key("TIME").MustTime() // RFC3339
  20. // Methods start with Must also accept one argument for default value
  21. // when key not found or fail to parse value to given type.
  22. // Except method MustString, which you have to pass a default value.
  23. v = cfg.Section("").Key("String").MustString("default")
  24. v = cfg.Section("").Key("BOOL").MustBool(true)
  25. v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
  26. v = cfg.Section("").Key("INT").MustInt(10)
  27. v = cfg.Section("").Key("INT64").MustInt64(99)
  28. v = cfg.Section("").Key("UINT").MustUint(3)
  29. v = cfg.Section("").Key("UINT64").MustUint64(6)
  30. v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
  31. v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339

What if my value is three-line long?

  1. [advance]
  2. ADDRESS = """404 road,
  3. NotFound, State, 5000
  4. Earth"""

Not a problem!

  1. cfg.Section("advance").Key("ADDRESS").String()
  2. /* --- start ---
  3. 404 road,
  4. NotFound, State, 5000
  5. Earth
  6. ------ end --- */

That’s cool, how about continuation lines?

  1. [advance]
  2. two_lines = how about \
  3. continuation lines?
  4. lots_of_lines = 1 \
  5. 2 \
  6. 3 \
  7. 4

Piece of cake!

  1. cfg.Section("advance").Key("two_lines").String() // how about continuation lines?
  2. cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4

Well, I hate continuation lines, how do I disable that?

  1. cfg, err := ini.LoadSources(ini.LoadOptions{
  2. IgnoreContinuation: true,
  3. }, "filename")

Holy crap!

Note that single quotes around values will be stripped:

  1. foo = "some value" // foo: some value
  2. bar = 'some value' // bar: some value

Sometimes you downloaded file from Crowdin has values like the following (value is surrounded by double quotes and quotes in the value are escaped):

  1. create_repo="created repository <a href=\"%s\">%s</a>"

How do you transform this to regular format automatically?

  1. cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
  2. cfg.Section("<name of your section>").Key("create_repo").String()
  3. // You got: created repository <a href="%s">%s</a>

That’s all? Hmm, no.

Helper methods of working with values

To get value with given candidates:

  1. v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
  2. v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
  3. v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
  4. v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
  5. v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9})
  6. v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9})
  7. v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
  8. v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339

Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates.

To validate value in a given range:

  1. vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
  2. vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
  3. vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
  4. vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9)
  5. vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9)
  6. vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
  7. vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
Auto-split values into a slice

To use zero value of type for invalid inputs:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0]
  3. vals = cfg.Section("").Key("STRINGS").Strings(",")
  4. vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
  5. vals = cfg.Section("").Key("INTS").Ints(",")
  6. vals = cfg.Section("").Key("INT64S").Int64s(",")
  7. vals = cfg.Section("").Key("UINTS").Uints(",")
  8. vals = cfg.Section("").Key("UINT64S").Uint64s(",")
  9. vals = cfg.Section("").Key("TIMES").Times(",")

To exclude invalid values out of result slice:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> [2.2]
  3. vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",")
  4. vals = cfg.Section("").Key("INTS").ValidInts(",")
  5. vals = cfg.Section("").Key("INT64S").ValidInt64s(",")
  6. vals = cfg.Section("").Key("UINTS").ValidUints(",")
  7. vals = cfg.Section("").Key("UINT64S").ValidUint64s(",")
  8. vals = cfg.Section("").Key("TIMES").ValidTimes(",")

Or to return nothing but error when have invalid inputs:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> error
  3. vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",")
  4. vals = cfg.Section("").Key("INTS").StrictInts(",")
  5. vals = cfg.Section("").Key("INT64S").StrictInt64s(",")
  6. vals = cfg.Section("").Key("UINTS").StrictUints(",")
  7. vals = cfg.Section("").Key("UINT64S").StrictUint64s(",")
  8. vals = cfg.Section("").Key("TIMES").StrictTimes(",")

Recursive Values

For all value of keys, there is a special syntax %(<name>)s, where <name> is the key name in same section or default section, and %(<name>)s will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions.

  1. NAME = ini
  2. [author]
  3. NAME = Unknwon
  4. GITHUB = https://github.com/%(NAME)s
  5. [package]
  6. FULL_NAME = github.com/go-ini/%(NAME)s
  1. cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon
  2. cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini

Python Multiline values

In case, you migrate service from Python and has some legacy configurations, don’t panic!

  1. cfg, err := ini.LoadSources(ini.LoadOptions{
  2. AllowPythonMultilineValues: true,
  3. }, []byte(`
  4. [long]
  5. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  6. foo
  7. bar
  8. foobar
  9. barfoo
  10. -----END RSA PRIVATE KEY-----
  11. `)
  12. /*
  13. -----BEGIN RSA PRIVATE KEY-----
  14. foo
  15. bar
  16. foobar
  17. barfoo
  18. -----END RSA PRIVATE KEY-----
  19. */

原文: https://ini.unknwon.io/docs/howto/work_with_values