-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from opentoys/f-20240201-chinese
add chinese tool set
- Loading branch information
Showing
11 changed files
with
8,038 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
.PHONY: test test-chinese | ||
|
||
test-chinese: | ||
go test -coverprofile=test-chinese.out github.com/opentoys/gocommon/chinese/ && \ | ||
go tool cover -html=test-chinese.out | ||
|
||
test-chinese-holiday: | ||
go test -coverprofile=test-chinese-holiday.out github.com/opentoys/gocommon/chinese/holiday && \ | ||
go tool cover -html=test-chinese-holiday.out | ||
|
||
test-chinese-idcard: | ||
go test -coverprofile=test-chinese-idcard.out github.com/opentoys/gocommon/chinese/idcard/ && \ | ||
go tool cover -html=test-chinese-idcard.out | ||
|
||
test-encoding-json: | ||
go test -coverprofile=test-encoding-json.out github.com/opentoys/gocommon/encoding/json/ && \ | ||
go tool cover -html=test-encoding-json.out | ||
|
||
test-otp-totp: | ||
go test -coverprofile=test-otp-totp.out github.com/opentoys/gocommon/otp/ && \ | ||
go tool cover -html=test-otp-totp.out | ||
|
||
|
||
test-crypto-aes: | ||
go test -coverprofile=test-crypto-aes.out github.com/opentoys/gocommon/crypto/aes/ && \ | ||
go tool cover -html=test-crypto-aes.out | ||
|
||
test-crypto-rsa: | ||
go test -coverprofile=test-crypto-rsa.out github.com/opentoys/gocommon/crypto/rsa/ && \ | ||
go tool cover -html=test-crypto-rsa.out | ||
|
||
test: | ||
test-chinese && test-chinese-holiday && test-chinese-idcard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package chinese | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"math/big" | ||
"strings" | ||
) | ||
|
||
const zero = "零元整" | ||
const maximum = "数位已超过最大值" | ||
|
||
var number_map = []string{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"} | ||
var unit_map = []string{"", "拾", "佰", "仟"} | ||
var big_unit_map = []string{"", "万", "亿", "兆", "京", "垓", "秭", "穰", "沟", "涧", "正", "载"} // 一、十、百、千、万、亿、兆、京、垓、秭(𥝱)、穰、沟、涧、正、载 | ||
var small_unit_map = []string{"角", "分", "厘", "毫", "丝", "忽", "微", "纤", "沙", "尘", "埃", "渺", "漠"} | ||
|
||
func DigitalPrice(v interface{}) string { | ||
var s string | ||
switch vv := v.(type) { | ||
case float64: | ||
s = new(big.Float).SetFloat64(vv).Text('f', 13) | ||
case float32: | ||
s = new(big.Float).SetFloat64(float64(vv)).Text('f', 13) | ||
case string: | ||
s = vv | ||
case *big.Int: | ||
s = vv.String() | ||
case *big.Float: | ||
s = vv.String() | ||
case int, int8, int32, int64, uint, uint8, uint16, uint32, uint64: | ||
s = fmt.Sprintf("%d", v) | ||
default: | ||
return maximum | ||
} | ||
if s == "0" { | ||
return zero | ||
} | ||
if len(s) > 46 { | ||
return maximum | ||
} | ||
var srr = strings.Split(s, ".") | ||
var integer, decimal, chinesei, chinesed string | ||
var zerocnt int | ||
integer = srr[0] | ||
if len(srr) > 1 { | ||
decimal = srr[1] | ||
} | ||
|
||
var length = len(integer) | ||
for i := 0; i < length; i++ { | ||
if integer[i] > 57 || integer[i] < 48 { | ||
return maximum | ||
} | ||
var num = integer[i] - 48 | ||
var unit = length - i - 1 // 当前数字的单位 | ||
var quotient = int(math.Floor(float64(unit) / 4)) // 1w为进位单位, 除 4 即为 万 亿 | ||
var remainder = unit % 4 // 1w为进位单位, 取模 4 即为 个 十 百 千 | ||
|
||
if num == 0 { | ||
zerocnt++ | ||
} else { | ||
// 处理前置的零 | ||
if zerocnt > 0 { | ||
chinesei += number_map[0] | ||
} | ||
zerocnt = 0 | ||
chinesei += number_map[num] + unit_map[remainder] | ||
} | ||
if remainder == 0 && zerocnt < 4 { | ||
chinesei += big_unit_map[quotient] | ||
} | ||
} | ||
|
||
// 价格为小数时,整数部分不显示 | ||
if length == 1 && integer < "1" { | ||
chinesei = "" | ||
} else { | ||
chinesei += "元" | ||
} | ||
|
||
if len(decimal) == 0 { | ||
return chinesei + "整" | ||
} | ||
|
||
zerocnt = 0 | ||
for i := 0; i < len(decimal); i++ { | ||
if decimal[i] > 57 || decimal[i] < 48 { | ||
return maximum | ||
} | ||
var num = decimal[i] - 48 | ||
if num > 0 { | ||
if zerocnt > 0 { | ||
chinesed += "零" | ||
zerocnt = 0 | ||
} | ||
chinesed += number_map[num] | ||
if i < 13 { | ||
chinesed += small_unit_map[i] | ||
} | ||
} else { | ||
zerocnt++ | ||
} | ||
} | ||
|
||
return chinesei + chinesed | ||
} | ||
|
||
func DigitalConvert(v interface{}) string { | ||
var s string | ||
switch vv := v.(type) { | ||
case float64: | ||
s = new(big.Float).SetFloat64(vv).Text('f', 13) | ||
case float32: | ||
s = new(big.Float).SetFloat64(float64(vv)).Text('f', 13) | ||
case string: | ||
s = vv | ||
case *big.Int: | ||
s = vv.String() | ||
case *big.Float: | ||
s = vv.String() | ||
case int, int8, int32, int64, uint, uint8, uint16, uint32, uint64: | ||
s = fmt.Sprintf("%d", v) | ||
default: | ||
return maximum | ||
} | ||
if s == "0" { | ||
return "零" | ||
} | ||
if len(s) > 46 { | ||
return maximum | ||
} | ||
var srr = strings.Split(s, ".") | ||
var integer, decimal, chinesei, chinesed string | ||
var zerocnt int | ||
integer = srr[0] | ||
if len(srr) > 1 { | ||
decimal = srr[1] | ||
} | ||
|
||
var length = len(integer) | ||
for i := 0; i < length; i++ { | ||
if integer[i] > 57 || integer[i] < 48 { | ||
return maximum | ||
} | ||
var num = integer[i] - 48 | ||
var unit = length - i - 1 // 当前数字的单位 | ||
var quotient = int(math.Floor(float64(unit) / 4)) // 1w为进位单位, 除 4 即为 万 亿 | ||
var remainder = unit % 4 // 1w为进位单位, 取模 4 即为 个 十 百 千 | ||
|
||
if num == 0 { | ||
zerocnt++ | ||
} else { | ||
// 处理前置的零 | ||
if zerocnt > 0 { | ||
chinesei += number_map[0] | ||
} | ||
zerocnt = 0 | ||
chinesei += number_map[num] + unit_map[remainder] | ||
} | ||
if remainder == 0 && zerocnt < 4 { | ||
chinesei += big_unit_map[quotient] | ||
} | ||
} | ||
|
||
if length == 1 && integer < "1" { | ||
chinesei = "零" | ||
} | ||
|
||
if len(decimal) == 0 { | ||
return chinesei | ||
} | ||
|
||
zerocnt = 0 | ||
for i := 0; i < len(decimal); i++ { | ||
if decimal[i] > 57 || decimal[i] < 48 { | ||
return maximum | ||
} | ||
var num = decimal[i] - 48 | ||
if num > 0 { | ||
if zerocnt > 0 { | ||
for j := 0; j < zerocnt; j++ { | ||
chinesed += "零" | ||
} | ||
zerocnt = 0 | ||
} | ||
chinesed += number_map[num] | ||
} else { | ||
zerocnt++ | ||
} | ||
} | ||
|
||
if len(chinesed) > 0 { | ||
chinesei += "点" | ||
} | ||
|
||
return chinesei + chinesed | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package chinese | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"math/big" | ||
"testing" | ||
) | ||
|
||
func TestDigitalConvert(t *testing.T) { | ||
var tests = []struct { | ||
input interface{} | ||
want string // expected error from Parse/Check or result from Eval | ||
}{ | ||
{1001, "壹仟零壹"}, | ||
{0, "零"}, | ||
{0.12312738, "零点壹贰叁壹贰柒叁捌"}, | ||
{false, "数位已超过最大值"}, | ||
{map[string]string{}, "数位已超过最大值"}, | ||
{[]string{}, "数位已超过最大值"}, | ||
{nil, "数位已超过最大值"}, | ||
{math.Pi, "叁点壹肆壹伍玖贰陆伍叁伍捌玖捌"}, | ||
{struct{}{}, "数位已超过最大值"}, | ||
{big.NewInt(123127312638), "壹仟贰佰叁拾壹亿贰仟柒佰叁拾壹万贰仟陆佰叁拾捌"}, | ||
{big.NewFloat(123127312638.123123), "数位已超过最大值"}, | ||
{"qweqweqwe", "数位已超过最大值"}, | ||
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "数位已超过最大值"}, | ||
{float64(99999999999999.1), "玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖点零玖叁柒伍"}, | ||
{float32(99999999999999.1), "壹佰兆零叁拾柒万陆仟捌佰叁拾贰"}, | ||
{"99999999999999.1", "玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖点壹"}, | ||
{"9999999999999999999999.112312312312312", "玖拾玖垓玖仟玖佰玖拾玖京玖仟玖佰玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖点壹壹贰叁壹贰叁壹贰叁壹贰叁壹贰"}, | ||
} | ||
|
||
for _, v := range tests { | ||
out := DigitalConvert(v.input) | ||
fmt.Println(out) | ||
if out != v.want { | ||
t.Fail() | ||
} | ||
} | ||
} | ||
|
||
func TestDigitalPrice(t *testing.T) { | ||
var tests = []struct { | ||
input interface{} | ||
want string // expected error from Parse/Check or result from Eval | ||
}{ | ||
{0, "零元整"}, | ||
{0.12312738, "壹角贰分叁厘壹毫贰丝柒忽叁微捌纤"}, | ||
{false, "数位已超过最大值"}, | ||
{map[string]string{}, "数位已超过最大值"}, | ||
{[]string{}, "数位已超过最大值"}, | ||
{nil, "数位已超过最大值"}, | ||
{struct{}{}, "数位已超过最大值"}, | ||
{big.NewInt(123127312638), "壹仟贰佰叁拾壹亿贰仟柒佰叁拾壹万贰仟陆佰叁拾捌元整"}, | ||
{big.NewFloat(123127312638.123123), "数位已超过最大值"}, | ||
{"qweqweqwe", "数位已超过最大值"}, | ||
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "数位已超过最大值"}, | ||
{float64(99999999999999.1), "玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖元零玖分叁厘柒毫伍丝"}, | ||
{float32(99999999999999.1), "壹佰兆零叁拾柒万陆仟捌佰叁拾贰元"}, | ||
{"99999999999999.1", "玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖元壹角"}, | ||
{"9999999999999999999999.112312312312312", "玖拾玖垓玖仟玖佰玖拾玖京玖仟玖佰玖拾玖兆玖仟玖佰玖拾玖亿玖仟玖佰玖拾玖万玖仟玖佰玖拾玖元壹角壹分贰厘叁毫壹丝贰忽叁微壹纤贰沙叁尘壹埃贰渺叁漠壹贰"}, | ||
} | ||
|
||
for _, v := range tests { | ||
out := DigitalPrice(v.input) | ||
if out != v.want { | ||
t.Fail() | ||
} | ||
} | ||
} |
Oops, something went wrong.