Parse currency / float string to float type based on locale in go

huangapple go评论66阅读模式
英文:

Parse currency / float string to float type based on locale in go

问题

我对如何将“浮点字符串”解析为浮点数感到困惑,基于了解国际化语言环境,但不对字符串做任何假设。

例如:德国人(包括我)写作“1.234,87”,而美国人写作“1,234.87”。在我的项目中,我知道我期望的语言环境,但我不想“硬编码”我对该语言环境如何书写这些内容的假设。

我不想使用正则表达式或字符串替换的方式。

是否有一种通用的方法来实现类似以下的功能:

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

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

非常感谢任何提示!

英文:

I am puzzled how to parse a "float-string" to a float, based on knowing the i18n-locale but not making presumptions about the string.

Example: Germans, like me, write "1.234,87" when Americans write "1,234.87". In my project I do know what locale I do expect, but I do not want to "hard code" what presumptions I have about how that local writes that stuff.

I would hate to do regexp/stringreplacements.

Is there a generic way to say something like

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

strconvdoesn't seem to have this functionality, neither does x/text/language

Grateful for any hints!

答案1

得分: 7

你最好使用标准库的strconv来处理。你可以创建自己的包装函数和区域设置。最终,我会添加更多的错误检查,并将其转化为自己的包,但这里只是一个想法。如果你还没有找到一个合适的包,很有可能你需要自己编写一个。对于一个更通用的解决方案,你需要考虑每种可能的输入,将其规范化为每个区域设置,并在其他人使用你的工具时强制执行这些规则。考虑到if语句和逻辑片段的数量,这将是一个更复杂的解决方案。好处是你知道strconv.ParseFloat期望的输入类型。所以你实际上只需要将用户输入转换为编程标准的格式。给定的数字大多是通用的,除了逗号和小数点之外,应该没有太多的用例。你甚至可以进一步概括,说有两种主要的格式,即欧洲等地和英美地区。德国使用的标准几乎是整个欧洲使用的标准。在这种假设下,实际上没有太多要做的,因为用例只有两种。

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)

}
英文:

Your best bet is the use the standard library's strconv. You can make your own wrappers and locale stuff. Eventually I'd add more error checking and turn this into it's own package, but here is an idea. If you haven't found a package yet there is a good chance you will have to write your own. For a more general solution, you'd have to think about every possible input.. normalize that per locale and enforce those rules when others are using your tools... That would be a more complex solution given the number of if statements and pieces of logic.. The good part is that you know the type of input strconv.ParseFloat expects.. So all you really have to do is take the user input and transform it to the programmatic standard http://floating-point-gui.de/formats/fp/. Given numbers are mostly universal, with the exception of commas and decimal points, there shouldn't be many use cases. You might even be able to generalize further and say there are two main formats.. https://www.quora.com/Why-do-some-countries-use-a-period-and-others-use-a-comma-to-separate-large-numbers, which is largely broken down to Europe et al and British/American, where German uses the standard almost all of Europe does. Under that assumption there isn't really much to do as the use cases comes down to 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)

}

答案2

得分: 1

/x/text不幸的是(公开地)没有提供你需要的所有内容,但我能够利用它构建出一个相当好用并与/x/text集成的东西,用于选择区域设置。

// 使用lxstrconv进行区域设置感知的数字解析
//
// 文档: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("١٬٢٣٤٫٥٦")))

}

英文:

/x/text unfortunately doesn't (publicly) expose everything you need for this, but I was able to leverage it to build something that works pretty well and integrates with /x/text for picking locale

// 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("١٬٢٣٤٫٥٦")))
}

huangapple
  • 本文由 发表于 2017年7月13日 19:18:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/45079074.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定