恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Go 人性化数字格式化完整指南:go-humanize 的尺寸、时间、序数与 SI 单位格式化实战
首页
资讯中心
/
Go 人性化数字格式化完整指南:go-humanize 的尺寸、时间、序数与 SI 单位格式化实战
Go 人性化数字格式化完整指南:go-humanize 的尺寸、时间、序数与 SI 单位格式化实战
发布时间:2026/9/17 17:05:04
Go 人性化数字格式化完整指南go-humanize 的尺寸、时间、序数与 SI 单位格式化实战【免费下载链接】inngestThe leading workflow orchestration platform. Run stateful step functions and AI workflows on serverless, servers, or the edge.项目地址: https://gitcode.com/GitHub_Trending/in/inngestgo-humanize是一套把枯燥丑陋的数字转换为人友好字符串的 Go 工具库它能将82854982变成83 MB将time.Time输出为3 days ago还能处理序数词、千分位逗号、浮点去尾零以及 SI 科学计数法。本文以仓库内 vendored 的 README.markdown 为主体骨架结合其位于 vendor/github.com/dustin/go-humanize 下的完整源码实现当前仓库在 go.mod 中声明依赖github.com/dustin/go-humanize v1.0.1逐函数讲解 API 用法、底层算法与边界行为让读者既能直接上手也能理解每个格式化函数背后的实现原理。安装与引入README 给出的引入方式非常直接使用go get拉取依赖导入路径为github.com/dustin/go-humanize包名use it as为humanizeimport github.com/dustin/go-humanize在 go.mod 中可以看到当前仓库将其以v1.0.1版本记录为 indirect 依赖并在vendor/github.com/dustin/go-humanize/目录下完整保留了该库的源码bytes.go、times.go、comma.go、si.go、ordinals.go、ftoa.go、big.go、bigbytes.go、number.go等。下面按功能模块逐一展开。字节大小格式化Sizes这是 go-humanize 最常用的功能把数字字节数转换为可读的容量字符串例如82854982可输出为83 MBSI 十进制或79 MiBIEC 二进制完全由你选择。fmt.Printf(That file is %s., humanize.Bytes(82854982)) // That file is 83 MB.从 bytes.go 的实现可以看到两个核心函数Bytes(s uint64) stringbytes.go以 1000 为底数后缀序列为B, kB, MB, GB, TB, PB, EB输出十进制SI容量。IBytes(s uint64) stringbytes.go以 1024 为底数后缀序列为B, KiB, MiB, GiB, TiB, PiB, EiB输出二进制IEC容量。两者的底层都调用同一个私有函数humanateBytesbytes.go其算法要点如下小于 10 字节时直接输出%d B不做单位换算使用lognbytes.go即math.Log(n) / math.Log(b)计算以 base 为底的对数取math.Floor得到数量级指数e数值按math.Floor(float64(s)/math.Pow(base, e)*100.5)/10保留一位小数四舍五入若结果小于 10 用%.1f %s否则用%.0f %s抹掉小数。单位常量与解析源码中还定义了两组可直接引用的常量IEC 常量bytes.goByte 1 (iota * 10)即KiByte1024、MiByte120、GiByte、TiByte、PiByte、EiByteSI 常量bytes.goIByte 1、KByte 1000、MByte、GByte、TByte、PByte、EByte按千进位。与之配套的解析函数ParseBytes(s string) (uint64, error)bytes.go可以把字符串反解回字节数例如42 MB - 42000000、42 mib - 44040192。它内部通过bytesSizeTablebytes.go查表该表同时收录了带完整后缀b/kib/kb/...和省略后缀ki/k/m/...的写法且解析时大小写不敏感如果数字部分含逗号会先剥离逗号遇到超出uint64上限的数值会返回too large错误未知单位则返回unhandled size name错误。相对时间格式化Timeshumanize.Time可以把一个time.Time转成相对时间表述例如12 seconds ago或3 days from nowfmt.Printf(This was touched %s., humanize.Time(someTimeInstance)) // This was touched 7 hours ago.README 提到该时间实现源自 Kyle Lemons 在某次 IRC 交流中的想法。从 times.go 可以看到完整的调用链Time(then time.Time) stringtimes.go是对RelTime(then, time.Now(), ago, from now)的封装RelTime(a, b time.Time, albl, blbl string) stringtimes.go提供自定义时间点与标签的能力如RelTime(timeInPast, timeInFuture, earlier, later) - 3 weeks earlierCustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) stringtimes.go允许你完全自定义量级切换表。量级表与二分查找RelTimeMagnitudetimes.go是一个包含D触发阈值时长、Format格式串含%s标签位与%d数量位、DivBy换算除数三个字段的结构体。默认量级表defaultMagnitudestimes.go按时间从短到长排列覆盖now、1 second ago、%d seconds ago、1 minute ago直到%d years ago和最终的a long while ago。格式化时CustomRelTime先根据a.After(b)判断取albl过去ago还是blbl未来from now然后用sort.Search对按D升序排列的量级表做二分查找找到第一个D diff的档位最后解析 Format 中的%s与%d占位符填充标签与数量。时间单位常量times.go中Month 30 * Day、Year 12 * Month、LongTime 37 * Year即一个月约 30 天、一年约 360 天这是相对时间表述的近似约定而非日历计算。序数词格式化Ordinals序数词功能源自一次 golang-nuts 邮件列表讨论用户希望输出排名后缀。其转换规则为0 - 0th 1 - 1st 2 - 2nd 3 - 3rd 4 - 4th [...]fmt.Printf(Youre my %s best friend., humanize.Ordinal(193)) // You are my 193rd best friend.实现位于 ordinals.go默认后缀为th仅当个位为 1/2/3 且整个数字不以 11/12/13 结尾时才分别替换为st/nd/rd从而正确处理11th、12th、13th这些特例。该函数接收int并返回字符串非负数直接拼接负数也会得到-1st之类的结果。千分位逗号格式化Commas想把逗号塞进数字里请便。 README 给出的行为示例0 - 0 100 - 100 1000 - 1,000 1000000000 - 1,000,000,000 -100000 - -100,000fmt.Printf(You owe $%s.\n, humanize.Comma(6582491)) // You owe $6,582,491.从 comma.go 可以读到三个层次的实现Comma(v int64) stringcomma.go对int64每三位插入逗号。一个值得注意的边界处理是math.MinInt64无法直接取反因此被特判返回-9,223,372,036,854,775,808comma.go负数先记录符号再对绝对值分组每组不足三位时用0左补齐Commaf(v float64) stringcomma.go浮点版本如Commaf(834142.32) - 834,142.32小数部分原样保留CommafWithDigits(f float64, decimals int) stringcomma.go限制小数位数如CommafWithDigits(834142.32, 1) - 834,142.3BigComma(b *big.Int) stringcomma.go为math/big的大整数提供同样的千分位格式配合 big.go 中的oom数量级计算可格式化超出int64范围的超大数。浮点去尾零格式化Ftoa标准库的%f会输出固定小数位导致2.24变成2.240000。Ftoa提供去除尾部零的更好看的浮点格式化fmt.Printf(%f, 2.24) // 2.240000 fmt.Printf(%s, humanize.Ftoa(2.24)) // 2.24 fmt.Printf(%f, 2.0) // 2.000000 fmt.Printf(%s, humanize.Ftoa(2.0)) // 2实现位于 ftoa.go先用strconv.FormatFloat(num, f, 6, 64)固定输出 6 位小数再由stripTrailingZerosftoa.go从尾部向前裁剪多余的0遇到小数点本身也一并去掉因此2.0输出为2。配套的FtoaWithDigits(num, digits)ftoa.go先裁剪到指定小数位再去除尾零。SI 科学计数法格式化SI notationSI 模块使用 SI 前缀metric prefix 格式化任意数量级的数字例如humanize.SI(0.00000000223, M) // 2.23 nM在 si.go 中前缀表siPrefixTablesi.go覆盖从qquecto10⁻³⁰到Qquetta10³⁰的全部 21 个 SI 前缀含µmicro这样的 Unicode 字符。核心函数ComputeSI(input float64) (float64, string)si.go计算最合适的指数指数按math.Floor(exponent/3)*3对齐到三位一组还处理了value 1000.0时应返回 1 M 而不是 1000 k的特例SI(input float64, unit string) stringsi.go使用Ftoa格式化数值并拼接前缀与单位如SI(1000000, B) - 1 MB、SI(2.2345e-12, F) - 2.2345 pFSIWithDigits(input, decimals, unit)si.go限制小数位如SIWithDigits(1000000, 0, B) - 1 MBParseSI(input string) (float64, string, error)si.go反向解析如ParseSI(2.2345 pF) - (2.2345e-12, F, nil)。其解析正则riParseRegexsi.go在init()中根据前缀表动态拼装而成。大数容量格式化BigBytes 系列README 未单独介绍、但同仓库内一并提供的能力是math/big大数版本。在 bigbytes.go 中BigBytes(s *big.Int) stringbigbytes.go与BigIBytes(s *big.Int) stringbigbytes.go分别以 1000/1024 为底后缀扩展到了ZB, YB, RB, QB对应 IEC 的ZiB, YiB, RiB, QiB可格式化任意大的字节数常量BigKiByte到BigQiBytebigbytes.go通过big.Int乘法逐级构建ParseBigBytesbigbytes.go用big.Rat做有理数运算后整除得到字节数避免浮点精度损失。其格式化辅助函数humanateBigBytesbigbytes.go依赖 big.go 中的oomm/oombig.go做基于big.Int的除模迭代来计算数量级。自定义模板格式化FormatFloat / FormatIntegernumber.go 提供了另一套按模板字符串渲染数字的能力改编自 gorhill 的 gist 实现。FormatFloat(format string, n float64) stringnumber.go使用#,###.##这类格式串控制千分位分隔符、小数分隔符与精度例如n 12345.6789#,###.## 12,345.67 #,###. 12,345 #,### 12345,678 默认格式 12,345.67该函数最高支持 9 位小数精度且对NaN、Infinity、-Infinity做了特判处理FormatInteger(format string, n int) stringnumber.go则是面向模板调用的整数便捷版本。英语专属函数humanize/english 子包README 说明以下函数位于humanize/english子包中即导入路径为github.com/dustin/go-humanize/english。复数化Plurals简单的英语复数规则english.PluralWord(1, object, ) // object english.PluralWord(42, object, ) // objects english.PluralWord(2, bus, ) // buses english.PluralWord(99, locus, loci) // loci english.Plural(1, object, ) // 1 object english.Plural(42, object, ) // 42 objects english.Plural(2, bus, ) // 2 buses english.Plural(99, locus, loci) // 99 lociPlural输出数字 单词组合PluralWord只输出单词本身两个函数都接受第三个参数作为不规则复数形式如locus的loci为空时按规则变化如bus - buses。词串连接Word series把逗号分隔的单词列表用连词连接成通顺的英文短语english.WordSeries([]string{foo}, and) // foo english.WordSeries([]string{foo, bar}, and) // foo and bar english.WordSeries([]string{foo, bar, baz}, and) // foo, bar and baz english.OxfordWordSeries([]string{foo, bar, baz}, and) // foo, bar, and bazWordSeries按a, b and c形式连接OxfordWordSeries则额外在最后一项前保留逗号牛津逗号风格。边界情况与使用注意事项综合上述源码使用 go-humanize 时有几个值得留意的点单位进制要选对Bytes走 1000SIIBytes走 1024IEC。存储厂商与操作系统的口径常不一致展示容量时务必与业务口径统一相对时间只是近似Month/Year分别按 30 天、360 天折算不涉及日历与时区跨月/跨年场景请自行评估是否符合预期序数词特例11/12/13 结尾的数字后缀永远是th11th、12th、13thOrdinal已正确处理Comma的int64下界math.MinInt64被特判为-9,223,372,036,854,775,808其余负数先取绝对值再分组解析函数会返回错误ParseBytes对未知单位返回unhandled size name对超出uint64的值返回too large使用时应处理 errorFtoa固定走 6 位小数先FormatFloat(f, 6)再裁剪尾零超过 6 位的小数位会被截断需要更多精度时可用FtoaWithDigits或直接使用strconv。小结go-humanize 是一个小而精的格式化工具库字节容量SI/IEC 双进制、相对时间、序数词、千分位逗号、浮点去尾零、SI 前缀以及大数版本一应俱全并附带反向解析函数与自定义量级表/格式模板。本文结合仓库中 vendor/github.com/dustin/go-humanize 的完整源码当前依赖版本见 go.mod逐一剖析了各 API 的调用关系与边界处理读者可以在 README.markdown 与上述各.go文件中继续深入研读原始实现与注释。【免费下载链接】inngestThe leading workflow orchestration platform. Run stateful step functions and AI workflows on serverless, servers, or the edge.项目地址: https://gitcode.com/GitHub_Trending/in/inngest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考