- 主题:用c++做了一个项目生不如死
【 在 hgoldfish 的大作中提到: 】
: 标 题: Re: 用c++做了一个项目生不如死
: 发信站: 水木社区 (Mon Jun 30 16:44:07 2025), 站内
:
: 比如 u8string 里面,想要迭代处理一个个 unicode 字符,一会是一个字节,一会儿是三个字节。
:
: unicode_string[i]
:
: 就这个简单的取下标,都是大麻烦。
如果有运行环境做保障的,根据 UTF-8 编码的校验功能
实现一个 u8string 的下标功能不难
--
FROM 120.253.228.*
python runtime中的编码应该是由locale/code page决定的。文件中的编码由文件的开头声明决定,默认是utf-8. Python will enable UTF-8 mode(运行时环境) by default from Python 3.15. 这个影响最大的是windows平台,因为mac和linux上,locale通常默认是utf-8.
peps.python.org/pep-3120/
peps.python.org/pep-0686/
在内部,python解释器应该是把各种编码转成某种unicode定长编码(比如ascii、utf-16、utf-32)来分别处理:
Python 3.3 and later (PEP 393):
peps.python.org/pep-0393/
The internal representation can be one of three forms:
- PyASCIIObject:
Used for strings containing only ASCII characters (code points up to 127). These are stored using 1 byte per character.
- PyCompactUnicodeObject:
Used for strings containing characters from the Basic Multilingual Plane (BMP), but not beyond. These are stored using 2 bytes per character (similar to UTF-16).
- PyUnicodeObject:
Used for strings containing characters outside the BMP (requiring code points up to 1,114,111). These are stored using 4 bytes per character (similar to UTF-32).
This flexible representation means that Python dynamically adjusts the internal storage width to minimize memory consumption, unlike older versions (Python 2 and early Python 3) that used a fixed-width UCS-2 or UCS-4 representation determined at compile time.
For example, a string containing only "hello" would be stored using 1-byte characters, while a string containing "hello?" would use a 4-byte representation because of the emoji character. This allows for efficient memory usage while maintaining the ability to represent the full range of Unicode characters.
==========
In Python 3.3 which implements PEP 393. The new representation will pick one or several of ascii, latin-1, utf-8, utf-16, utf-32, generally trying to get a compact representation.
==========
python对字符串的这种处理方式——程序员可以只使用utf-8编码,而内部将字符串拆成ascii、utf-16、utf-32定长编码——既对程序员屏蔽了细节,又使用定长编码来节约存诸空间、加快下标取值速度和方便计算字符串长度,值得C++借鉴。
C++的步子太小了,还把宽窄字符串这种内存细节暴露给程序员,这不是一种现代化的处理思路。
【 在 easior 的大作中提到: 】
: Python 的字符串底层应该是建立在 C 的多字节流之上的吧
: C 的这一套处理方案依赖于本地策略集,也容易出现乱码
: Python 3 预设了所有编码都是 UTF-8,不知道虚拟机如何处理运行环境的?
: ...................
--
修改:seablue FROM 111.200.40.*
FROM 111.200.40.*
哈哈哈,我可能天生不适合搞技术,做了四五年的开发,全部是Cpp和C,还特么有汇编,至今有阴影。
--
FROM 121.229.104.*
你就把u16string拿来用有啥不行的吗?
java的string就是u16啊
【 在 seablue 的大作中提到: 】
: python runtime中的编码应该是由locale/code page决定的。文件中的编码由文件的开头声明决定,默认是utf-8. Python will enable UTF-8 mode(运行时环境) by default from Python 3.15. 这个影响最大的是windows平台,因为mac和linux上,locale通常默认是utf-8.
: peps.python.org/pep-3120/
: peps.python.org/pep-0686/
: 在内部,python解释器应该是把各种编码转成某种unicode定长编码(比如ascii、utf-16、utf-32)来分别处理:
: Python 3.3 and later (PEP 393):
: peps.python.org/pep-0393/
: The internal representation can be one of three forms:
: - PyASCIIObject:
: Used for strings containing only ASCII characters (code points up to 127). These are stored using 1 byte per character.
: - PyCompactUnicodeObject:
: Used for strings containing characters from the Basic Multilingual Plane (BMP), but not beyond. These are stored using 2 bytes per character (similar to UTF-16).
: - PyUnicodeObject:
: Used for strings containing characters outside the BMP (requiring code points up to 1,114,111). These are stored using 4 bytes per character (similar to UTF-32).
: This flexible representation means that Python dynamically adjusts the internal storage width to minimize memory consumption, unlike older versions (Python 2 and early Python 3) that used a fixed-width UCS-2 or UCS-4 representation determined at compile t
: ime.
: For example, a string containing only "hello" would be stored using 1-byte characters, while a string containing "hello?" would use a 4-byte representation because of the emoji character. This allows for efficient memory usage while maintaining the abilit
: y to represent the full range of Unicode characters.
: ==========
: In Python 3.3 which implements PEP 393. The new representation will pick one or several of ascii, latin-1, utf-8, utf-16, utf-32, generally trying to get a compact representation.
: ==========
: python对字符串的这种处理方式——程序员可以只使用utf-8编码,而内部使用将字符串拆为成ascii、utf-16、utf-32定长编码——既对程序员屏蔽了细节,又使用定长编码来节约存诸空间、加快下标取值速度和方便计算字符串长度,值得C++借鉴。
: C++的步子太小了,还把宽窄字符串这种内存细节暴露给程序员,这不是一种现代化的处理思路。
--
修改:kirbyzhou FROM 114.247.175.*
FROM 114.247.175.*
我前面的贴子说了:原来的utf-16现在不够用了,于是扩成了变长变码。
那既然用了变长编码,为啥不用utf-8?毕竟utf-8自带同步信息,而且在ascii内空间效率更高,也不用再区分宽窄字符串。
java/js的unicode string是u16,这是历史遗留问题。所以现在很尴尬。
python和apple的swift是少有的默认以utf-8处理字符的语言。swift是因为比较新,历史包袱小,python是因为破坏了兼容性,用了很长时间才从python2过渡到python3,现在已不再区分宽窄字符。大多数语言为了保持兼容性,没有将默认的字符串处理方式改成utf-8,只是把utf-16扩充成变长编码方式,不再依赖它的定长编码算法。比如JavaScript从 ES2015 开始添加了字符串方法和正则表达式标志,允许从与编码无关的角度处理字符串。——这就不依赖于定长编码方式了。
【 在 kirbyzhou 的大作中提到: 】
: 你就把u16string拿来用有啥不行的吗?
: java的string就是u16啊
--
修改:seablue FROM 111.200.40.*
FROM 111.200.40.*
也不算尴尬。
Java 的 u16string 在互联网时代存储汉字更高效。
【 在 seablue 的大作中提到: 】
: 我前面的贴子说了:原来的utf-16现在不够用了,于是扩成了变长变码。
: 那既然用了变长编码,为啥不用utf-8?毕竟utf-8自带同步信息,而且在ascii内空间效率更高。
: java的string是u16,这是历史遗留问题。所以现在很尴尬。
: ...................
--
FROM 120.41.147.*
表情符号要么没法存,要么超出了两字节。所以utf-16是一个残次品。
【 在 hgoldfish 的大作中提到: 】
: 也不算尴尬。
: Java 的 u16string 在互联网时代存储汉字更高效。
--
修改:seablue FROM 111.200.40.*
FROM 111.200.40.*
但 utf-8 也很尴尬啊。印象中表情符需要 6 个 utf-8 字节才能存得下?
【 在 seablue 的大作中提到: 】
: 表情符号要么没法存,要么超出了两字节。所以utf-16是一个残次品。
--
FROM 120.41.147.*
这有什么尴尬的?编码空间不够了,自然就得上长编码。
像gbk那样,自己两字节定长是爽了,但是不顾别国。所以出现了各种utf. 就是为了把大家的文字都放一个编码空间,同时显示。
utf-16也是同样的问题,它在两字节内(UCS-2)已经满员了,为了处理表情符号,只能扩充。要怪就怪unicode/utf-16目光短浅(其实也是为了追求那点可怜的空间效率:IEEE曾引入了更大的 31 位空间和一种编码(UCS-4),每个字符需要 4 个字节。这遭到了Unicode 联盟的抵制,一方面因为每个字符 4 个字节会浪费大量内存和磁盘空间,另一方面一些制造商已经在 2 个字节/字符技术上投入了大量资金)。当年认为只要2字节(65536个编码空间)就能编码地球上的所有文字,没想到今天的unicode已经发展到了16万个字符(其中10万个是汉字)。unicode可以很方便地增补扩充,因为人家只是负责出版文本,增补时多印几页纸就行了。可是与之对应的utf-16就没那么容易扩充,有不少程序已经固定了(java),有了历史代码,在这种情况下,如果utf-16的编码方式变了,这些程序就很尴尬。为了避免utf-16的缺点,出现了utf-32,它就是为了取代utf-16而来的,可是让这些程序用utf-32,有些人又舍不得那点编码空间。
而且utf-16对英文也是2字节编码,为了节省空间,c++中处理英文用的是ascii(窄字符)。这不是跟python内部一样的拆分思路吗?只不过在c++中交给了程序员自己处理。
在C++/java中,
英文字母:ascii (窄字符:单字节)
基本平面内的2.8万个中文:u16 (宽字符:双字节)
表情符号:u32 (宽字符:四字节)
这跟python内部的方法是一样的。
=====
from wiki: Windows API以及许多编程环境(例如Java和Qt )都使用 UTF-16。UTF-16 的
可变长度特性,加上大多数字符的长度并非可变(因此很少测试可变长度),导致了许多软
件(包括 Windows 本身)出现错误。
由于最常用的字符都包含在 BMP 中,代理对的处理通常未经彻底测试。这会导致持续存在的 bug 和潜在的安全漏洞,即使是在热门且备受好评的应用软件中也是如此(例如CVE - 2008-2938、CVE -2012-2135)。
一个“字符”可以使用任意数量的 Unicode 码位。[ 21 ]例如,一个表情符号标志字符占用 8 个字节,因为它“由一对 Unicode 标量值构成” [ 22 ](这些值位于 BMP 之外,每个值需要 4 个字节)。UTF-16 无法辅助“计算字符数”或“测量字符串的宽度”。
对于东亚语言来说,UTF-16 通常被认为比UTF-8更节省空间,因为它用两个字节来表示 UTF-8 中占用三个字节的字符。由于实际文本包含许多空格、数字、标点符号、标记(例如网页标记)和控制字符,而这些字符在 UTF-8 中只占用一个字节,因此 UTF-16 的这种说法仅适用于人为构建的密集文本块。[需要引用]对于天城文和孟加拉语来说,情况可能更糟,因为它们包含多字母单词,所有字母在 UTF-8 中占用三个字节,而在 UTF-16 中仅占用两个字节。
此外,中文 Unicode 编码标准GB 18030对所有语言(而不仅仅是中文)始终生成与 UTF-16 大小相同或更小的文件(它通过牺牲自同步来实现这一点)。
自Windows 10 版本 1903(或内部版本17035)起,API 中已经可以使用 UTF-8,[ 28 ]尽管大多数软件(例如Windows 文件资源管理器)仍然使用 UTF-16 API。微软表示,“UTF-16 [..] 是 Windows 对针对多平台的代码施加的独特负担” [ 29 ]文件和网络数据往往是 UTF-16、UTF-8 和传统字节编码的混合。
短信实际上使用的是 UTF-16。文档中指定的是 UCS-2,但表情符号必须使用 UTF-16 才能正常工作。[ 30 ]
【 在 hgoldfish 的大作中提到: 】
: 但 utf-8 也很尴尬啊。印象中表情符需要 6 个 utf-8 字节才能存得下?
--
修改:seablue FROM 111.200.40.*
FROM 111.200.40.*
超出2字节就超呗。
比utf-8的1~4字节处理起来可是方便太多了。
【 在 seablue 的大作中提到: 】
: 表情符号要么没法存,要么超出了两字节。所以utf-16是一个残次品。
--
FROM 114.247.175.*