Golang.org/x库初探2——text库

     Golang有一个很有意思的官方库,叫golang.org/x,x可能是extends,experimental,总之是一些在官方库中没有,但是又很有用的库。最近花点时间把这里有用的介绍一下。

  1. Golang.org/x库初探1——image库
  2. Golang.org/x库初探2——text库
  3. Golang.org/x库初探3——sync库

    text库主要提供strings库的一系列Unicode和国际化适配的替代升级方案。常用的库如下:

golang.org/x/text/language

language库定义了BCP 47的语言标签支持,这里的语言指的自然语言,英语,中文等。

所谓的BCP 47 就是zh-CN这种格式的前面是语言,后面是地域的标识符(地域可选)

language库定义了Match等操作,这样你可以用来匹配最佳的语言,常用的是http中,用户在头部通过Accept-Language标识了他希望使用的语言,这样我们在服务端可以和服务器支持的语言进行匹配,寻找最合适的语言。

这个库虽然介绍的功能主要是Match功能,但同时也是cases等其他库用于标识语言的基础库,所以第一个介绍这个库。当然如果我们要做一个国际化程序,也可以把国际化标识这块,也使用lanuage库作为通用标识,以增强兼容性和标准化。

golang.org/x/text/cases

cases库用于支持国家化的大小写转换,写法如下

var case = cases.Title(language.English, cases.NoLower)
fmt.Print(case.String("beforeThis")) //BeforeThis

这里的Title就是一般的Title case的用法。Title函数支持传入附加Option,上面传入了NoLower参数,用于标识除了首字母之外,其他非小写字母不需要转化为小写。

相比于标准库,cases的具体效果还是有区别,比如 下面的测试例:

func TestCases(t *testing.T) {
	var tested = "beforeThis"
	fmt.Println("基础库Title:", strings.ToTitle(tested))
	var case1 = cases.Title(language.English)
	fmt.Println("不带Option的cases Title:", case1.String(tested))
	var case2 = cases.Title(language.English, cases.NoLower)
	fmt.Println("带Option的cases Title:", case2.String(tested))
}

输出如下:

基础库Title: BEFORETHIS
不带Option的cases Title: Beforethis
带Option的cases Title: BeforeThis

 基础库的ToTitle做完全大写转换还是有问题的,cases库就正常一点,对首字母大写即可。

而ToLower和ToUpper表现一致。

而国际化方面,主要针对几种语言做了适应性处理,主要是西欧语言的差异,这里就不多讲了,需要的同学可以从Title函数点进去看代码,有详细的注释

titleInfos = []struct {
		title     mapFunc
		lower     mapFunc
		titleSpan spanFunc
		rewrite   func(*context)
	}{
		{title, lower, isTitle, nil},                // und
		{title, lower, isTitle, afnlRewrite},        // af
		{aztrUpper(title), aztrLower, isTitle, nil}, // az
		{title, lower, isTitle, nil},                // el
		{ltUpper(title), ltLower, noSpan, nil},      // lt
		{nlTitle, lower, nlTitleSpan, afnlRewrite},  // nl
		{aztrUpper(title), aztrLower, isTitle, nil}, // tr
	}

golang.org/x/text/number

number库主要定义了很多帮助格式化数字的帮助函数,这个应该我们用的多点,可用的东西包括格式化函数和选项两类,格式化函数包括:

Decimal 格式化逗号分隔的整数,例如1,234,567这种

Engineering

类科学计数法(但指数部分最多有三位),输出类似这样:12.345678 × 10⁶

PerMille

直接转成千分比数字,例如120‰
Percent        百分比

Scientific

科学计数法,输出类似这样:1.2345678 × 10⁷
 

另外,提供了多个Option来自定义输出:

FormatWidth

指定数字转换后的字符串宽度,例如

 number.PerMille(0.12, number.FormatWidth(10))会输出

“      120‰”

IncrementString

一种宽泛的四舍五入算法,例如

number.PerMille(0.16, number.IncrementString("0.3"))会输出0.3,number.PerMille(0.14, number.IncrementString("0.3"))会输出0.0

MaxFractionDigits

最大小数位数(四舍五入)
MaxIntegerDigits  最大整数位数(直接裁剪多余部分)

MinIntegerDigits

最小整数位数(补零)
MinFractionDigits 最小小数位数(补零)
NoSeparator 不分组数字

Precision

浮点数精度,负数为小数位数,正数为整数位数

总的用法就是和message包配合,像fmt一样使用,例如官方库的案例

func TestNumber(t *testing.T) {
	p := message.NewPrinter(language.Chinese)

	p.Printf("%v bottles.\n", number.Decimal(3321.96, number.Precision(2)))
}

其中第二行展示了格式化函数和选项的用法。

这个库我们基本可以在很多需要格式化数字的地方用到了,原来很多很复杂的自定义写法都可以用这个来处理,这个库还提供了从上述标准函数派生自定义的入口NewFormat,大家可以从库中查找使用。

golang.org/x/text/message

上面说了message库提供了一个类似fmt的国际化解决方案,同时可以和number等配合,做更多的格式化以及本地化适应的功能。

但同时他还是一个可以用于多语言翻译的库,在提供国际化方面有很大用处。

例如我们有这么一个帮助:

func TestNumber(t *testing.T) {
	pZh := message.NewPrinter(language.Make("zh"))
	pEn := message.NewPrinter(language.Make("en"))

	message.SetString(language.English, "您输入的%s不符合要求\n", "The input value %s is not legal")

	pZh.Printf("您输入的%s不符合要求\n", "1234")
	pEn.Printf("您输入的%s不符合要求\n", "1234")
}
=== RUN   TestNumber
您输入的1234不符合要求
The input value 1234 is not legal--- PASS: TestNumber (0.00s)
PASS

可以发现,英文的Printer直接转成了英文打印。

但是注意,这个定义必须完全一致才生效,所以官方的例子如下:

message.SetString(language.Dutch, "You have chosen to play %m.", "U heeft ervoor gekozen om %m te spelen.")
	message.SetString(language.Dutch, "basketball", "basketbal")
	message.SetString(language.Dutch, "hockey", "ijshockey")
	message.SetString(language.Dutch, "soccer", "voetbal")
	message.SetString(language.BritishEnglish, "soccer", "football")

	for _, sport := range []string{"soccer", "basketball", "hockey"} {
		for _, lang := range []string{"en", "en-GB", "nl"} {
			p := message.NewPrinter(language.Make(lang))
			fmt.Printf("%-6s %s\n", lang, p.Sprintf("You have chosen to play %m.", sport))
		}
		fmt.Println()
	}

他首先用了一个Sprintf来把预定义国家化字符串进行转换,再做的Printf。

这个例子里还有一点说明的是,他使用了一个"%m"来说明传入变量要取国际化值,如果改成%s则不转换。

同时,text库提供了一个可编译库gotext用于在代码中获得所有的字符串,用于简化国际化的工作。

golang.org/x/text/encoding

这个库,估计中文环境就用的很多了,就是传说中的编码库,用来做UTF-8,GBK,BIG5转换的,而且他把编码转换的框架进行了标准化,可以做不同编码格式的转换,这样就不需要再去用iconv等麻烦的东西了。

例如encoding下面的简体中文库simplifiedchinese提供了GB18030和GBK两个编码类,两个类都可以使用NewEncoder或NewDecoder来初始化一个编码器或者解码器,例如下面的例子,打开一个utf-8的文件,并转成gbk的:

	f, err := os.Open("utftext.txt")
	if err == nil {
		var out *os.File
		out, err = os.Create("gbk.txt")
		if err == nil {
			//将utf的reader转成gbk的reader
			r := simplifiedchinese.GBK.NewDecoder().Reader(f)
			//进一步读取拷贝
			io.Copy(out, r)

			out.Close()
			f.Close()
		}
	}

当然,NewDecoder().Transform()直接按byte数组转换也是可以的。

其他更多

当然,text下还有很多内容,我个人觉得用处不大,就不细讲了,包括

  1. currency: 货币支持库
  2. date: 国际化日期相关库
  3. search:本地化搜索支持,西文中差异较多,中文少
  4. secure:特殊用处下的文字有效性判断
  5. runes,collate:utf-8相关库
  6. unicode: unicode相关库
  7. transform: 转换库,可配合unicode下的各种定义来做特殊字符移除等功能
  8. 其他的功能库:feature、width
  9. 更多的编码库,包括韩文、日文等

详细的可以看官方库介绍

总的我认为:

  1. 编码转换可以直接用encoding库
  2. 国际化用message库
  3. Upper、Lower、Title等转换看需要用cases库或者标准strings库
  4. number库的功能很强大,在金融等应用场景下用处多多。

猜你喜欢

转载自blog.csdn.net/baijiafan/article/details/128669152
今日推荐