☰
《仓颉编程基础及应用》扩展阅读:用 std.convert 的 format 函数掌握仓颉字符串的复杂格式化
2026/10/14 17:04:50 网站建设 项目流程
  • 示例工程
  • 教程

【免费下载链接】仓颉编程基础及应用_陈波_何睿_重庆大学

《仓颉编程基础及应用》,清华大学出版社,2025年9月第1版: 1. 随书源代码; 2. PPT; 3.在线扩展阅读资料。

项目地址:https://gitcode.com/Cangjie-SIG/Cangjie_Basics_Application
点击查看免费下载

将一个数值对象转换成指定样式的字符串(规定宽度、对齐、精度、进制、符号前缀等)是控制台输出与数据展示中高频出现的需求。本文基于《仓颉编程基础及应用》随书源码仓库中的扩展阅读文档,系统讲解仓颉std.convert包为Float32、Float64、Int32、Int64、UInt32、UInt64等类型扩展提供的format成员函数,完整拆解fmt格式串的[flags][width][.precision][specifier]四段式语法,并给出仓库中可直接编译运行的 9 个配套示例工程,帮助读者掌握仓颉中宽度补齐、左右对齐、零填充、进制转换与科学计数法等格式化实战技能。

1. 格式化概念与 format 成员函数

将一个对象转换成对应的字符串对象的过程称之为格式化(format)。在仓颉中,std.convert包为Float32、Float64、Int32、Int64、UInt32、UInt64等类型扩展实现了format成员函数。在导入std.convert包后,再执行这些对象的format成员函数,即可将对象“转换”成对应的字符串表达形式。

上述format成员函数的签名为format(fmt: String): String,其fmt参数是一个字符串类型的参数,用于指定转换格式。理解这个函数有两点需要注意:

  • 它是扩展成员函数:format并不是这些数值类型自带的成员,导入std.convert之后,Int32、Float64等对象才“拥有”该成员函数,这体现了仓颉通过包导入引入扩展能力的语言机制;
  • 它不修改原对象:pi.format(x)只是根据pi的值以及格式串x的要求生成并返回一个新的字符串对象,原数值对象在函数执行前后类型和值都保持不变。

2. 简单格式化示例

下述示例(对应仓库工程 BookSourceCode/CH2/StrFormat)将浮点数对象pi按指定格式转换成字符串并打印至屏幕:

package StrFormat import std.convert //导入std标准库下的format包 main(): Int64 { let pi:Float64 = 3.141592653589793238462643383279 let s1 = pi.format(".4"); let s2 = pi.format("+20.10") println(s1); print(s2) //s1, s2均为String类型 return 0 }

上述代码的执行结果为:

3.1416 +3.1415926536

逐行解析:

  • 第 2 行:导入std标准模块下的convert(格式化)包。程序第 6 行所使用的格式化函数是由该包定义的;
  • 第 5 行:定义圆周率不可变变量pi,为尽可能提高存储精度,这里使用了Float64类型;
  • 第 6 行:在导入了std.convert之后,pi作为Float64类型的对象,便拥有了成员函数format;
  • 第 7 行:将格式化结果字符串s1和s2通过println和print函数打印至屏幕。

结合执行结果观察:

  • pi.format(".4")将pi格式化,生成了将pi保留 4 位小数的字符串"3.1416"。format函数的参数".4"为一个字符串字面量,它表明转换格式为“保留 4 位小数”。不难看出,3.1415926… 在格式化保留 4 位小数的过程中被四舍五入,变成了 3.1416;
  • pi.format("+20.10")将pi格式化为显示正负号(+)、总宽度 20 个字符、保留 10 位小数、右对齐的字符串,不足部分使用空格补齐(即执行结果第 2 行中+3.1415926536左侧的若干空格)。

3. 格式化参数 fmt 的语法格式

根据仓颉文档,format(fmt: String): String函数的fmt参数用于指定格式化参数,这些参数用于规定转换结果的宽度、对齐方式、精度等信息。格式化参数fmt的语法格式为:

[flags][width][.precision][specifier]

其中,方括号表示这些字段为可选,即格式化参数并不需要完整包含上述 4 个字段。四个字段的位置是固定的:标志位在前、宽度次之、精度(以.引导)再次之、进制/记数 specifier 在最后。后文分别对四类字段逐一展开。

4. flags 标志位

flags字段可以包含"-"、"+"、"#"、"0"四个字符中的 1 个或多个。

4.1 "-":左对齐

"-"适用于Int、UInt、Float等类型,表示左对齐。对应示例工程 BookSourceCode/CH2/Alignment:

package Alignment import std.convert main(): Int64 { var c:Int32 = -17 let s1 = c.format("-20") //20个字符,左对齐 println(s1) let s2 = c.format("20") //20个字符,默认右对齐 print(s2) return 0 }

执行结果为:

-17 -17

解析:

  • 第 6 行:格式化参数"-20"中的"-"属于flags字段,表示转换结果应为左对齐;"20"则属于width字段,表示结果字符串应包含 20 个字符,不足部分用空格补齐(因此第一行的-17后补了 17 个空格);
  • 第 9 行:格式化参数未要求左对齐,默认右对齐。如执行结果第 2 行所见,format成员函数通过在左侧补充空格的方式满足 20 的宽度要求。

4.2 "+":正值输出加号

"+"适用于Int、UInt、Float,表示对正数输出+号。对应示例工程 BookSourceCode/CH2/Plus:

package Plus import std.convert main(): Int64 { var v1:Float32 = 7.1287 let s1 = v1.format("+") //给正值使用+,结果中会出现+号 println(s1) var v2:Float32 = -7.1287 let s2 = v2.format("+") //给负值使用+ print(s2) return 0 }

执行结果为:

+7.128700 -7.128700

可见正数结果被加上+号前缀;如执行结果第 2 行所见,当给负值使用"+"时,于转换结果不构成影响(负号-本就存在)。

4.3 "#":为转换结果添加进制符号

"#"为转换结果添加进制符号。具体地,为二进制结果补充0b或者0B,为 16 进制结果补充0x或者0X,为 8 进制结果补充0o或者0O。当输出结果为 10 进制时,不起作用。该符号预期与specifier中的进制符号x、b等联合使用。对应示例工程 BookSourceCode/CH2/Sharp:

package Sharp import std.convert main(): Int64 { var v = 125 println(v.format("#x")) println(v.format("x")) //x为specifier,意为16进制 println(v.format("#B")) println(v.format("B")) //B为specifier,意为2进制 //未指定进制,即为10进制,#号不起作用 print(v.format("#")) return 0 }

执行结果为:

0x7d //x导致了7d, #号附加了0x 7d //没有#号,就没有0x 0B1111101 //B导致2进制结果,#号附加了0B 1111101 //没有#号,就没有0B 125 //对于10进制,#号不起作用

4.4 "0":空位补零

"0"适用于Int、UInt和Float,用于在空位补0。对应示例工程 BookSourceCode/CH2/ZeroLeading:

package ZeroLeading import std.convert main(): Int64 { var v = 72.6386654 println(v.format("020")) //20个字符,不足前端补0 print(v.format("20")) //20个字符,不足前端补空格 return 0 }

执行结果为:

0000000000072.638665 72.638665

可以看出,宽度不足的补位默认使用空格,加上"0"标志后则改为补0,常用于生成固定位宽的时间戳、编号等展示。

5. width 宽度

v.format("20")中的20即为宽度。宽度应为正整数,适用于Int、UInt、Float等类型。宽度前有"-"表示左对齐,否则右对齐。对应示例工程 BookSourceCode/CH2/Width:

package Width import std.convert main(): Int64 { var v = 123456 println(v.format("20")) //自身占6个字符,前方补了14个空格 print(v.format("+20")) //连同+号占7个字符,前方补了13个空格 return 0 }

执行结果为:

123456 +123456

两点值得注意:

  • 宽度指的是整个结果字符串的总字符数,而非数值本身占用的位数;
  • 当同时使用"+"标志时,符号也计入总宽度——"+123456"连同+号占 7 个字符,故前方只补了 13 个空格。

6. precision 精度

精度常用于指定浮点数小数点后的数字位数,如果不指定,则默认输出 6 位小数(第 2 节示例中Float32输出7.128700即为默认 6 位小数的体现)。对应示例工程 BookSourceCode/CH2/Precision:

package Precision import std.convert main(): Int64 { var v:Float64 = 12345.678987654321 println(v.format(".3")) //3位小数,四舍五入 println(v.format(".5")) //5位小数,四舍五入 print(v.format(".0")) //0位小数,四舍五入 return 0 }

执行结果为:

12345.679 12345.67899 12346

可以看到,精度截断时按四舍五入处理:.3使12345.6789…进位为12345.679;.0表示不保留小数,结果直接进位为整数12346。

7. specifier 进制与记数方式

7.1 b、B、o、O、x、X:指定进制(Int 与 UInt)

b、B、o、O、x、X用于指定进制,适用于Int和UInt类型:b为小写 2 进制、B为大写 2 进制;o为小写 8 进制、O为大写 8 进制;x为小写 16 进制、X为大写 16 进制;未指定时默认 10 进制。如前所述,上述进制符号可与flags中的"#"号配合使用。对应示例工程 BookSourceCode/CH2/Base:

package Base import std.convert main(): Int64 { var v = 4571 println(v.format("b")) println(v.format("B")) println(v.format("o")) println(v.format("O")) println(v.format("x")) print(v.format("X")) return 0 }

执行结果为:

1000111011011 1000111011011 10733 10733 11db 11DB

其中大小写 specifier 的差异主要体现在 16 进制的数字字母上(x输出11db,X输出11DB);2 进制与 8 进制本身只含数字,大小写结果相同。

7.2 e、E、g、G:科学计数法与自适应记数(Float)

e、E、g、G适用于Float类型:e表示小写的科学计数法,E表示大写的科学计数法;g或G源于 general(常规),表示让仓颉在科学计数法和普通 10 进制计数法中自动选择较为恰当的表达方式。对应示例工程 BookSourceCode/CH2/Scientific:

package Scientific import std.convert main(): Int64 { var a = 1234.5678987654321 println(a.format("e")) println(a.format(".3E")) println(a.format("g")) //自适应:常规10进制 var b = 228989289.1234234 print(b.format(".2G")) //自适应:科学计数法 return 0 }

执行结果为:

1.234568e+03 //e 1.235E+03 //E 1234.57 //g 2.3E+08 //.2G

从结果可以看出g/G的“自适应”行为:当数值较适中时(1234.5678…)选择常规 10 进制记数并截断为1234.57,当数值量级较大时(228989289.1234…)则自动切换为科学计数法2.3E+08,避免了普通记数方式下过长的数字串。

8. 格式化参数速查表

将全文内容汇总为速查表,便于日常编码时对照使用:

字段位置可选取值适用类型作用
flags最前-、+、#、0(可组合)-/+/0适用 Int、UInt、Float;#配合进制 specifier-左对齐;+正值加号;#添加0x/0b/0o等进制前缀;0空位补零
widthflags 之后正整数Int、UInt、Float结果总宽度,不足时补空格(或按0标志补零);无-时默认右对齐
.precisionwidth 之后以.引导的非负整数Float小数点后位数,默认 6 位,超出四舍五入
specifier最后b/B、o/O、x/X;e/E、g/G前者用于 Int、UInt;后者用于 Float指定进制或科学计数法/自适应记数方式;缺省为 10 进制

四个字段均为可选,可自由组合,例如第 2 节中的"+20.10"即为flags(+) + width(20) + .precision(10)的组合。

9. 随书源码工程的验证方式

文中所有示例均来自《仓颉编程基础及应用》随书源码目录 BookSourceCode/CH2,每个示例是独立的 cjpm 工程(含 cjpm.toml 与src/main.cj)。从工程配置 BookSourceCode/CH2/StrFormat/cjpm.toml 看,output-type为executable、cjc-version为0.57.3;仓库 README.md 说明源码整体按照仓颉 LTS 1.0.0 标准编写。因此适用前提是:本地安装兼容的仓颉工具链(cjc/cjpm)后,在任一示例工程目录下(如BookSourceCode/CH2/StrFormat)使用 cjpm 构建并运行即可复现本文各节的执行结果。

与format主题相关但属于不同技术面的扩展阅读,可参考同目录下的 使用 format-hex 以 16 进制格式查看文件内容(该文档讨论的是 Windows PowerShell 的format-hex命令,与本文的std.convert格式化函数并非同一技术),以及 仓颉位运算相关示例——理解了format的进制输出后,位运算结果用format("b")、format("x")展示会十分直观。

10. 小结

  • std.convert包通过扩展机制为整数与浮点类型提供format(fmt: String): String成员函数,将数值对象按指定样式转换为String,且不改变原对象;
  • 格式串语法为[flags][width][.precision][specifier],四段均为可选:flags(-左对齐、+正值加号、#进制前缀、0补零)控制标志,width控制总宽度与补齐,.precision控制小数位数,specifier控制进制(b/B/o/O/x/X)或浮点记数方式(e/E/g/G);
  • 随书源码 BookSourceCode/CH2 下 StrFormat、Alignment、Plus、Sharp、ZeroLeading、Width、Precision、Base、Scientific 共 9 个工程与本文示例一一对应,可直接编译运行验证各格式化参数的实际效果。
  • 示例工程
  • 教程

【免费下载链接】仓颉编程基础及应用_陈波_何睿_重庆大学

《仓颉编程基础及应用》,清华大学出版社,2025年9月第1版: 1. 随书源代码; 2. PPT; 3.在线扩展阅读资料。

项目地址:https://gitcode.com/Cangjie-SIG/Cangjie_Basics_Application
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询