【问题标题】:Parse currency / float string to float type based on locale in go根据 go 语言环境将货币/浮点字符串解析为浮点类型
【发布时间】:2017-12-18 03:28:05
【问题描述】:

我很困惑如何将“浮点字符串”解析为浮点数,基于知道 i18n 语言环境但不对字符串做出假设。

示例:像我一样,德国人写“1.234,87”,而美国人写“1,234.87”。在我的项目中,我确实知道我期望的语言环境,但我不想“硬编码”我对本地如何编写这些东西的假设。

我不想做正则表达式/字符串替换。

有没有一种通用的说法,比如

myFloat := ParseFloatByLocale("1.234,76", "DE-DE")
// myFloat => 1234.76

strconv似乎没有这个功能,x/text/language也没有

感谢任何提示!

【问题讨论】:

  • 也许你可以以某种方式使用它,github.com/leekchan/accounting。我在所有项目中都使用它。
  • 感谢@prematch,但似乎会计工作浮动->字符串,我正在寻找字符串->浮动
  • 我想说最好只使用golang.org/pkg/strconv ...f, err := strconv.ParseFloat("3.1415", 64)。您可能需要规范化您的字符串并将它们传递给...如果您想围绕 strconv 创建一个实现函数 ParseFloatByLocale 的包
  • 这个问题很容易概括为解析本地化百分比值和日期/时间格式。

标签: string parsing go type-conversion


【解决方案1】:

最好的办法是使用标准库的strconv。您可以制作自己的包装器和语言环境。最终我会添加更多的错误检查并将其变成它自己的包,但这是一个想法。如果您还没有找到一个包,那么您很有可能必须自己编写一个包。对于更通用的解决方案,您必须考虑每个可能的输入.. 规范化每个区域设置并在其他人使用您的工具时强制执行这些规则...考虑到 if 语句和片段的数量,这将是一个更复杂的解决方案逻辑.. 好的部分是您知道strconv.ParseFloat 期望的输入类型.. 所以您真正需要做的就是获取用户输入并将其转换为编程标准http://floating-point-gui.de/formats/fp/。给定的数字大多是通用的,除了逗号和小数点,不应该有很多用例。您甚至可以进一步概括并说有两种主要格式..https://www.quora.com/Why-do-some-countries-use-a-period-and-others-use-a-comma-to-separate-large-numbers,主要分为欧洲等和英国/美国,德国使用几乎所有欧洲的标准。在这种假设下,随着用例减少到 2 个,实际上并没有太多工作要做。

package main

import (
    "fmt"
    "log"
    "strconv"
    "strings"
)

func normalizeGerman(old string) string {
    s := strings.Replace(old, ",", ".", -1)
    return strings.Replace(s, ".", "", 1)
}
func normalizeAmerican(old string) string {
    return strings.Replace(old, ",", "", -1)
}

var locale map[string]func(string) string

func init() {
    locale = make(map[string]func(string) string)
    locale["DE-DE"] = normalizeGerman
    locale["US"] = normalizeAmerican
}

func main() {
    var f, f2 float64
    var err error
    // german
    if val, ok := locale["DE-DE"]; ok {
        f, err = strconv.ParseFloat(val("1.234,87"), 64)
        if err != nil {
            log.Fatal("german fail", err)
        }
    }
    //american
    if val, ok := locale["US"]; ok {
        f2, err = strconv.ParseFloat(val("1,234.87"), 64)
        if err != nil {
            log.Fatal("american fail", err)
        }
    }

    fmt.Println(f, f2)

}

【讨论】:

  • 感谢这篇详细的帖子。现在我很清楚,我没有错过标准库包,我真的考虑开始编写通用包。谢谢!
  • 我很想知道我会如何处理这个潜在的包裹,因为我提到了它。 github.com/marcsantiago/StringToFloat 这是一个不错的开始,我想如果您想继续或想要一个更好的例子
  • 利用 golang.org/x/text 在此处实现了这一点:play.golang.org/p/Mkl7NOE_VbW
【解决方案2】:

/x/text 不幸的是并没有(公开)公开你需要的一切,但我能够利用它来构建一些运行良好并与 /x/text 集成以选择语言环境的东西

// Locale-aware number parsing with lxstrconv
//
// Docs: https://godoc.org/tawesoft.co.uk/go/lxstrconv

package main

import (
    "fmt"
    "golang.org/x/text/language"
    "tawesoft.co.uk/go/lxstrconv"
)

func checked(f float64, e error) float64 {
    if e != nil {
        panic(e)
    }
    return f
}

func main() {
    dutch   := lxstrconv.NewDecimalFormat(language.Dutch)
    british := lxstrconv.NewDecimalFormat(language.BritishEnglish)
    arabic  := lxstrconv.NewDecimalFormat(language.Arabic)

    fmt.Printf("%f\n", checked(british.ParseFloat("1,234.56")))
    fmt.Printf("%f\n", checked(dutch.ParseFloat("1.234,56")))
    fmt.Printf("%f\n", checked(arabic.ParseFloat("١٬٢٣٤٫٥٦")))
}

【讨论】:

    猜你喜欢
    • 2020-05-22
    • 2021-06-30
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多