查看: 110|回复: 3

Python阿拉伯数字转圆圈数字Unicode偏移转换实现教程

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在自动生成文档大纲、制度文件或Markdown目录时,带圈数字(①⑪⑳)常用于最低层级小标题。Python标准库没有直接提供该转换方法,网上多数代码仅支持1到10,且缺少参数校验和统一封装。本文将基于Unicode偏移公式,实现一套覆盖1到20的圆圈数字转换工具,包括基础函数、安全容错版本、工具类封装以及业务整合方案。

## 原理:Unicode编码偏移

带圈数字在Unicode中是独立字符,编码区间为:

- ① U+2460  ← 对应数字1
- ⑩ U+2469  ← 对应数字10
- ⑪ U+246A  ← 对应数字11
- ⑳ U+2473  ← 对应数字20

规律非常简洁:数字n对应的代码点 = 0x2460 + n - 1。例如n=11时,0x2460+10=0x246A,即字符⑪。利用该偏移公式,无需手动维护字典,一行chr()即可获取圆圈字符。

## 基础转换函数

以下函数接受整数1~20,返回对应圆圈字符,并包含类型和范围校验。
  1. def num_to_circle_char(n: int) -> str:
  2.     """
  3.     阿拉伯数字 1~20 转换为圆圈数字 ①②③…⑳
  4.     :param n: 输入整数,范围 1 ~ 20
  5.     :return: 圆圈单个字符
  6.     """
  7.     if not isinstance(n, int):
  8.         raise TypeError("输入必须为整数类型")
  9.     if not 1 <= n <= 20:
  10.         raise ValueError("当前仅支持 1 ~ 20 的数字转换圆圈序号")
  11.     code_point = 0x2460 + n - 1
  12.     return chr(code_point)
  13. if __name__ == "__main__":
  14.     test_list = [1, 5, 10, 13, 18, 20]
  15.     for num in test_list:
  16.         res = num_to_circle_char(num)
  17.         print(f"{num} → {res}")
复制代码

运行输出:
  1. 1 → ①
  2. 5 → ⑤
  3. 10 → ⑩
  4. 13 → ⑬
  5. 18 → ⑱
  6. 20 → ⑳
复制代码

## 异常容错安全版(生产推荐)

业务代码不希望因非法输入直接崩溃,可改用安全版:超出范围或类型错误时返回默认值,不抛异常。
  1. def num_to_circle_char_safe(n: int, default: str = "") -> str:
  2.     """
  3.     安全版,越界返回默认值
  4.     :param n: 目标数字
  5.     :param default: 超出范围/类型错误时返回内容
  6.     :return: 圆圈字符或默认值
  7.     """
  8.     try:
  9.         if not isinstance(n, int):
  10.             return default
  11.         if 1 <= n <= 20:
  12.             code_point = 0x2460 + n - 1
  13.             return chr(code_point)
  14.         return default
  15.     except Exception:
  16.         return default
  17. # 测试
  18. print(num_to_circle_char_safe(21))      # 空
  19. print(num_to_circle_char_safe(0, "无")) # 无
  20. print(num_to_circle_char_safe("abc"))   # 空
  21. print(num_to_circle_char_safe(12))      # ⑫
复制代码

## 统一工具类封装

将圆圈数字转换与已有的“中文数字”、“第X篇”、“第X部分”整合到一个工具类中,便于项目管理。
  1. class ChapterNumUtil:
  2.     digits = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
  3.     @classmethod
  4.     def num_to_plain_chinese(cls, n: int) -> str:
  5.         """纯中文数字:1→一、15→十五、100→一百"""
  6.         if not isinstance(n, int) or n < 1 or n > 100:
  7.             raise ValueError("仅支持1~100整数")
  8.         if n == 100:
  9.             return "一百"
  10.         ten = n // 10
  11.         unit = n % 10
  12.         if ten == 0:
  13.             return cls.digits[unit]
  14.         elif ten == 1:
  15.             return "十" if unit == 0 else f"十{cls.digits[unit]}"
  16.         else:
  17.             return f"{cls.digits[ten]}十" if unit == 0 else f"{cls.digits[ten]}十{cls.digits[unit]}"
  18.     @classmethod
  19.     def num_to_chinese_article_title(cls, n: int) -> str:
  20.         return f"第{cls.num_to_plain_chinese(n)}篇"
  21.     @classmethod
  22.     def num_to_chinese_part_title(cls, n: int) -> str:
  23.         return f"第{cls.num_to_plain_chinese(n)}部分"
  24.     @classmethod
  25.     def num_to_circle_char(cls, n: int) -> str:
  26.         if not isinstance(n, int) or not 1 <= n <= 20:
  27.             raise ValueError("圆圈序号仅支持1~20")
  28.         return chr(0x2460 + n - 1)
  29.     @classmethod
  30.     def num_to_circle_char_safe(cls, n: int, default="") -> str:
  31.         try:
  32.             return cls.num_to_circle_char(n)
  33.         except (TypeError, ValueError):
  34.             return default
  35. # 统一调用示例
  36. util = ChapterNumUtil
  37. print(util.num_to_chinese_article_title(3))  # 第三篇
  38. print(util.num_to_chinese_part_title(12))    # 第十二部分
  39. print(util.num_to_circle_char(7))            # ⑦
  40. print(util.num_to_circle_char(19))           # ⑲
  41. print(util.num_to_circle_char_safe(99, "超出范围"))  # 超出范围
复制代码

## 实战场景:大纲层级搭配

制度文档中常需多级编号,可结合工具类实现:

- 层级0:num_to_chinese_article_title(2) → 第二篇
- 层级1:num_to_chinese_part_title(3) → 第三部分
- 层级2:普通阿拉伯数字 1、2、3
- 层级3:小数 1.1、1.2
- 层级6:num_to_circle_char(2) → ②

示例代码:
  1. article = ChapterNumUtil.num_to_chinese_article_title(2)
  2. circle = ChapterNumUtil.num_to_circle_char(2)
  3. print(f"{article}\n  4.1 管理要求\n    {circle} 业务办理流程")
复制代码

输出:
  1. 第二篇
  2.   4.1 管理要求
  3.     ② 业务办理流程
复制代码

## 常见踩坑

1. **超过20无标准字符**:Unicode只定义了①到⑳(U+2460~U+2473),21及以上没有标准圆圈字符。业务设计时建议控制层级不超过20,若必须使用21以上,改用(21)括号文本替代。
2. **不要用字符串拼接(1)代替**:(1)是三个普通符号,与原生圆圈字符在字体排版、对齐、导出Word/Markdown时视觉差异明显。规范文档必须使用Unicode圆圈字符。
3. **浮点数类型问题**:10.0虽数值等于10,但类型为float,会触发类型校验。调用前需强制转整数 int(num)。
4. **编码兼容性**:主流编辑器、Word、WPS、浏览器均完美支持U+2460~U+2473,无乱码风险。

## 拓展:批量生成全部圆圈序号

快速打印1~20所有圆圈字符用于调试:
  1. circle_list = [num_to_circle_char(i) for i in range(1, 21)]
  2. print(circle_list)
  3. # ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳']
复制代码

## 总结

圆圈数字本质是连续Unicode字符,通过固定偏移公式0x2460+n-1快速计算,无需字典映射。基础函数严格限制1~20,安全容错版本适配生产环境。与中文数字、第X篇等封装在同一工具类中,命名统一,多层级大纲生成时便于调用。原生Unicode圆圈字符排版规范,适合自动化生成制度手册或Markdown文档。注意序号上限20,超出需改用括号格式作为备选方案。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python阿拉伯数字转圆圈数字Unicode偏移转换实现教程

这个教程非常实用!以前我处理目录大纲时,遇到带圈数字只能手动打或者去网上找转义表,最多支持到⑩。楼主直接用Unicode偏移一行chr()搞定,还做了类型校验和范围限制,安全版的设计对生产环境也很友好。工具类中顺便把中文数字和“第X篇”也整合进来,感觉很贴合实际文档生成需求。请问如果我想扩展到圆圈数字①到⑳之外的字符(比如带圈字母),是否也可以用类似的偏移公式?
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python阿拉伯数字转圆圈数字Unicode偏移转换实现教程

楼主分享的帖子非常实用,尤其是Unicode偏移公式的思路很清晰,直接chr()就能搞定,比手动维护字典优雅多了。安全容错版本考虑到了生产环境,避免抛异常导致程序中断,这个设计很周到。工具类里还整合了中文数字转换,方便统一管理章节编号,对文档生成场景很有帮助。 请问如果未来需要支持21以上的圆圈数字(比如Unicode里还有带括弧的⓪⑲⑳之后就没有了),是否只能通过组合字符或自定义字体来实现?有没有其他替代方案?
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python阿拉伯数字转圆圈数字Unicode偏移转换实现教程

非常好的教程,原理清晰、代码规范,从基础函数到容错版本再到工具类封装,层层递进,很适合直接用在项目里。之前自己写这类转换总要手动维护字典,看到Unicode偏移公式后确实清爽很多。安全版的做法也很实用,生产环境里确实需要避免因为非法输入直接抛异常。另外,工具类里顺便封装了中文数字和“第X篇”的转换,这个思路很棒,一套工具解决多种标题目的是很省事的。感谢分享!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-9 10:58 , Processed in 0.035087 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部