解决 Python 的字符串 center ljust rjust 在面对中文时的 bug
方法一:修改内置 str 的方法,能更灵活的定制,更准确地判断 CJK 字符,全局有效。甚至还能把转义序列也兼容了。
def modify_str():
import gc, ctypes
def curse(klass, attr, value):
"""
这里用的是 forbiddenfruit 库的 curse 简化了一下,省去了下载第三方库
用于修改内置 class 的属性
"""
dikt = gc.get_referents(klass.__dict__)[0]
old_value = dikt.get(attr, None)
old_name = '_c_%s' % attr
dikt[attr] = value
if old_value:
dikt[old_name] = old_value
dikt[attr].__name__ = old_value.__name__
dikt[attr].__qualname__ = old_value.__qualname__
ctypes.pythonapi.PyType_Modified(ctypes.py_object(klass))
CJK_CHARACTERS = [ # 定义 CJK 字符的区间
(0x3400, 0x4DB5), # CJK Unified Ideographs Extension A
(0x4E00, 0x9FA5), # CJK Unified Ideographs
(0x9FA6, 0x9FBB), # CJK Unified Ideographs
(0xF900, 0xFA2D), # CJK Compatibility Ideographs
(0xFA30, 0xFA6A), # CJK Compatibility Ideographs
(0xFA70, 0xFAD9), # CJK Compatibility Ideographs
(0x20000, 0x2A6D6), # CJK Unified Ideographs Extension B
(0x2F800, 0x2FA1D), # CJK Compatibility Supplement
(0xFF00, 0xFFEF), # 全角ASCII、全角中英文标点、半宽片假名、半宽平假名、半宽韩文字母
(0x2E80, 0x2EFF), # CJK部首补充
(0x3000, 0x303F), # CJK标点符号
(0x31C0, 0x31EF), # CJK笔划
(0x2F00, 0x2FDF), # 康熙部首
(0x2FF0, 0x2FFF), # 汉字结构描述字符
(0x3100, 0x312F), # 注音符号
(0x31A0, 0x31BF), # 注音符号(闽南语、客家语扩展)
(0x3040, 0x309F), # 日文平假名
(0x30A0, 0x30FF), # 日文片假名
(0x31F0, 0x31FF), # 日文片假名拼音扩展
(0xAC00, 0xD7AF), # 韩文拼音
(0x1100, 0x11FF), # 韩文字母
(0x3130, 0x318F), # 韩文兼容字母
(0x1D300, 0x1D35F), # 太玄经符号
(0x4DC0, 0x4DFF), # 易经六十四卦象
(0xA000, 0xA48F), # 彝文音节
(0xA490, 0xA4CF), # 彝文部首
(0x2800, 0x28FF), # 盲文符号
(0x3200, 0x32FF), # CJK字母及月份
(0x3300, 0x33FF), # CJK特殊符号(日期合并)
(0x2700, 0x27BF), # 装饰符号(非CJK专用)
(0x2600, 0x26FF), # 杂项符号(非CJK专用)
(0xFE10, 0xFE1F), # 中文竖排标点
(0xFE30, 0xFE4F), # CJK兼容符号(竖排变体、下划线、顿号)
]
CJK_CHARACTERS.sort()
CJK_CHARACTERS_LIST = [a for tup in CJK_CHARACTERS for a in tup]
def char_width(char):
'''按一个 CJK 占两个宽度算,返回字符宽度'''
unicode = ord(char)
if unicode < CJK_CHARACTERS_LIST[0]:
return 1
for index, item in enumerate(CJK_CHARACTERS_LIST):
if unicode < item: break
if index % 2:
return 2
return 1
def calculate(string):
'''字符串总宽度'''
return sum([char_width(char) for char in string])
import re
csi_pattern = re.compile("(?:\x9b|\033\[)\d*(?:;\d*)*[A-Za-z]") # 用于匹配转义序列
# 重新定义 str 的三个方法:
def center(self: str, width, *args, **kwargs):
width += sum([len(csi) for csi in csi_pattern.findall(self)]) # 加上转义序列的补偿
if len(self) < width:
width -= (calculate(self) - len(self))
return getattr(self, '_c_'+'center')(width, *args, **kwargs)
def ljust(self: str, width, *args, **kwargs):
if len(self) < width:
width -= (calculate(self) - len(self))
return getattr(self, '_c_'+'ljust')(width, *args, **kwargs)
def rjust(self: str, width, *args, **kwargs):
if len(self) < width:
width -= (calculate(self) - len(self))
return getattr(self, '_c_'+'rjust')(width, *args, **kwargs)
curse(str, 'center', center)
curse(str, 'ljust', ljust)
curse(str, 'rjust', rjust)
modify_str()
print('这是中文字符'.center(30, '*'))
print('这是\x9b42m绿色背景\x9b0m字符'.center(30, '*'))
print('English Words'.center(30, '*'))
print('Привет! Как дела?'.center(30, '*'))

方法二:先用 gbk 编码,调整后,再解码。局限性较大,不能准确判断 CJK 符号,不易兼容其它国家的语言。
# 一般中文宽度是英文的两倍,带有中文的字符串使用 center ljust rjust 会出现宽度非常不一致
# 我们希望中文可以按两个宽度计算
# 可以利用 gbk 是双字节编码,中文字符占2字节,英文字符占1字节
# 将字符串用 gbk 编码后,再用 center ljust rjust,最后用 gbk 解码,就可以得到视觉上中英文一致的宽度
# 需要注意的是,有一些偏僻字使用 gbk 是无法编码的,例如:
print('\x9b42m 展示 \x9b0m')
print('这是中文字符'.encode('gbk').center(30, b'*').decode('gbk'))
print('English Words'.encode('gbk').center(30, b'*').decode('gbk'))
解决 Python 的字符串 center ljust rjust 在面对中文时的 bug的更多相关文章
- 解决python中write()函数向文件中写中文时出现乱码的问题
今天看<python编程从入门到实践>的第10章文件.异常,在做练习的时候,向文件中写内容,但是写中文就不行,后来在百度上查了众多资料,解决方法如下: 解决:在open()函数中添加一个e ...
- python center, ljust, rjust
例子 >>> s = "jihite" >>> s.center(, "*") '**jihite**' >>& ...
- 【python】 字符串转小写(含汉字等时仍work)
def mylower(str): outstr = ""; strlen = len(str); idx = 0; while idx < strlen: if ord(s ...
- Python: ljust()|rjust()|center()字符串对齐
通过某种对齐方式来格式化字符串 ①对于基本的操作,可以使用字符串的ljust(),rjust(),center() ②函数format()同样可以用来很容易的对齐字符串,使用<,>,~
- python之字符串
字符串与文本操作 字符串: Python 2和Python 3最大的差别就在于字符串 Python 2中字符串是byte的有序序列 Python 3中字符串是unicode的有序序列 字符串是不可变的 ...
- Python数据类型——字符串
概论 字符串顾名思义就是一串字符,由于Python中没有“字符”这种数据类型,所以单个的字符也依然是字符串类型的.字符串可以包含一切数据,无论是能从键盘上找到的,还是你根本都不认识的.与数一样,字符串 ...
- python基础-字符串(str)类型及内置方法
字符串-str 用途:多用于记录描述性的内容 定义方法: # 可用'','''''',"","""""" 都可以用于定义 ...
- python中字符串内置方法
字符串类型 作用:定义姓名.性别等 定义方式: s='lzs' #\n换行 \t缩进4个空格 \r回退上一个打印结果,覆盖上一个打印结果 加上一个\让后面的\变得无意义 内置方法: (优先掌握) 1. ...
- python之字符串,列表,字典,元组,集合内置方法总结
目录 数字类型的内置方法 整型/浮点型 字符串类型的内置方法 列表的内置方法 字典的内置方法 元组的内置方法 集合类型内置方法 布尔类型 数据类型总结 数字类型的内置方法 整型/浮点型 加 + 减 - ...
- Python格式化字符串~转
Python格式化字符串 在编写程序的过程中,经常需要进行格式化输出,每次用每次查.干脆就在这里整理一下,以便索引. 格式化操作符(%) "%"是Python风格的字符串格式化操作 ...
随机推荐
- Windows下Zookeeper安装使用
Windows下Zookeeper安装使用 ZooKeeper是一种分布式协调服务,用于管理大型主机. 在分布式环境中协调和管理服务是一个复杂的过程. ZooKeeper通过其简单的架构和API解决了 ...
- [复现]2021 DASCTF X BUUOJ 五月大联动-PWN
[复现]2021 DASCTF X BUUOJ 五月大联动 由于我没ubuntu16就不复现第一个题了,直接第二个 正常的off by one from pwn import * context.os ...
- java8利用流和lambda表达式对list遍历处理
java8的lambda表达式提供了一些方便list操作的方法,主要涵盖分组.过滤.求和.最值.排序.去重. 优点: (1) 简洁,跟之前的传统写法对比,能少写不少代码; (2) 易并行计算.尤其适用 ...
- SpringBoot解决跨域方案
SpringBoot解决跨域的几种方式 跨域资源共享(CORS):通过修改Http协议header的方式,实现跨域.说的简单点就是,通过设置HTTP的响应头信息,告知浏览器哪些情况在不符合同源策略的条 ...
- Spring:现代Java开发的必备框架
目录 Spring:现代Java开发的必备框架 Spring创建bean的生命周期以及对应的接口和注解 Spring使用三级缓存解决循环依赖的原理 Spring使用三级缓存创建bean的过程 Spri ...
- 搭建react的架手架
1.回顾 cnpm i @vue/cli -g ----- 4的脚手架 ------ webpack 4 cnpm i @vue/cli@3 -g ----- 3的脚手架 ------ webpack ...
- 强大的 apt-get 命令
强大的 apt-get 命令(小结) 一.ubuntu下管理软件最方便的非 apt-get 工具莫属了,它的常见用法稍微整理一下供以后参考(详细见 man apt-get ): 1.更新源,升级软件和 ...
- 《HelloTester》第4期
1.前言 终于到了谈面试的部分了! 我在这也说明一下,有同学说之前简历篇的时候一直在说项目的介绍,而面试官真正关心的是技术啊?我在这做个解释,因为我写的这些文章主要针对的是软件测试的同学,所以其他职位 ...
- pandas之面属行统计
描述统计学(descriptive statistics)是一门统计学领域的学科,主要研究如何取得反映客观现象的数据,并以图表形式对所搜集的数据进行处理和显示,最终对数据的规律.特征做出综合性的描述分 ...
- stm32串口烧录程序
Step1:将BOOT0设置为1,BOOT1设置为0,mcuisp软件不使用STR和DTR烧录 Step2:程序下载完成后,再将BOOT0手动跳帽接GND,复位,这样STM32才可以从Flash中启动 ...