Skip to content

Commit

Permalink
Merge pull request #1 from opentoys/f-20240201-chinese
Browse files Browse the repository at this point in the history
add chinese tool set
  • Loading branch information
alonelucky authored Feb 2, 2024
2 parents 7b961cf + e05f3df commit c09c925
Show file tree
Hide file tree
Showing 11 changed files with 8,038 additions and 0 deletions.
33 changes: 33 additions & 0 deletions Makefile
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
198 changes: 198 additions & 0 deletions chinese/digital.go
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
}
71 changes: 71 additions & 0 deletions chinese/digital_test.go
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()
}
}
}
Loading

0 comments on commit c09c925

Please sign in to comment.