注册 登录
编程论坛 VFP论坛

Strconv(C, N)的第2个参数N是5或12时,我一看就有点儿头大!

cssnet 发布于 2022-11-16 22:23, 1559 次点击
讲真,遇到Unicode字符,应尽量地转换至UTF-8来处理,而尽量不要转换至Unicode(UCS-2)。
原因很简单:
UTF-8的英文字符,完全兼容ANSI,这样一来,许多涉及字符串的代码,几乎不需改动或改动很小,即可升迁至UTF-8;而UCS-2则很麻烦,英文的0h00就搞得人肝肠寸断、梨花带雨的。
12 回复
#2
csyx2022-11-17 17:08
如果不清楚原因,肯定会头大

首先,windows 所有涉及字符串的 api 函数,都实现了 A 和 W 两套,其中的 W 系列只认 utf-16 编码,没有认 utf-8 的第三套
其次,vfp ide 只认 ansi 字符,因此传递给 W 系列的 win32api 函数时,ansi 字符串必须用 strconv(ANSI字符串, 5) 转换成 utf-16 编码
同理,对于 utf-8 编码的字符串,vfp 必须用 strconv(UTF-8字符串, 12) 转成 utf-16 编码再交给 W 函数去处理

是否“应该尽量地转换至UTF-8来处理”?不尽然!首先你得搞清楚这些英文缩写的含义
unicode:是一种标准,包括字符集和编码方案,unicode 13 标准定义了 143859 个字符、符号的庞大字符集,最新的 14 版又增加了一些 Emoji 表情
utf-8:是 unicode 的一种编码方案, 采用 1-6字节的变长编码格式, 常用字符在 1-3 字节之间,例如:ascii 字符都是一字节,中文通常是三字节。
ucs-2,同样是一种编码方案,采用固定两字节编码,也就限制了只能有 65536 种可能性,因此它无法完整包含所有 unicode 字符,已被废弃不用
utf-16,它是 ucs-2 的扩充方案,对于 BMP 平面内的字符,与 ucs-2 完全兼容,对于非 BMP 字符,采用四字节来表示,Windows 使用此方案

由于英语的霸主地位,网络上大量的文本(包括网页源代码)都是 ascii 字符,从而 utf-8 的 ascii 单字节表示法优势尽显,因此网络上 utf-8 为王
但在本机上处理字符串时,这种多字节编码导致的解析复杂度就成为了缺点,而 utf-16 的定长编码成为优势。Windows 使用 utf-16 来表示 unicode 不可能是比尔靠拍脑袋做出的决定

网络上充斥着大量将这些名词混为一谈的文章,甚至在 vfp help、msdn 等文档中,微软也将 unicode 与 utf-16 划等号!前者可能是本身概念不清导致,后者则是由于其 unicode 是采用 utf-16 来现实的而有意为之,帝国主义永远都用自己的标准来做国际标准的野蛮由此可见一斑

至于用什么编码来存储数据,要依使用场景来决定
把【A 啊 𠅤】这三个字符用记事本分别保存为 utf-8 和 utf-16 (当然,你找不到 utf-16,原因见上一行)格式的文本文件,如果要你自己写一个函数来判断有几个字符,你认为那种编码方案更简单?
#3
cssnet2022-11-17 17:38
自Windows NT开始采用Unicode(UCS-2)编码,大约是在15~20年前;再稍过一些时日,Java诞生,也采用了Unicode(UCS-2)编码。

这其实是个悲剧!鬼佬让中国人给骗了。呵呵。

那时,天还很蓝,草地还很绿,PM 2.5还远远不曾超标……鬼佬们天真地以为,只要用2字节16位65536种字符,就能包含地球上一切字符,于是欣然采用了Unicode(UCS-2)编码。

后来,他们才发觉自己好傻好天真!单单是中文字符,总数就已远超十万个!然后,这才亡羊补牢地搞什么utf-16、utf-32之类古里古怪的编码方案,说实话,大错已铸成,积重难返了。

相比utf-16,其实utf-8优势相当明显,特别是针对英语而言尤其如此。用在网络传输,utf-8也非常优秀、安全、方便,可称得上舍我其谁!

Windows API的W系列采用utf-16编码,其实是相当不智的。
#4
cssnet2022-11-17 18:00
UTF-8编码,最优雅、也最最令人喜爱之处是:

UTF-8不会主动插入“硬编码字符”0x00和0xFF,这意味着,即使是调用年代最远古的C代码字符处理函数,也不会遇到特别麻烦;而至于UCS-2、utf-16、utf-32则不成的,到处是0x00,一切字符处理函数,只要遇到utf-16,就必须统统推倒重来!所以说,Windows API的W系列采用utf-16编码,那纯粹是自寻烦恼!自找不痛快!!

#5
csyx2022-11-17 18:18
帖子最后我列举了一个例子,自己用 vfp 代码实现原生函数 LenC 的 unicode 版,分别用 utf-8 和 utf-16 作为输入参数测试一下,哪种编码格式更有优势?要在 vfp 端处理 unicode 字符,有很大可能需要自己来实现这些功能

另一方面,Windows 使用 utf-16 编码格式是既定的事实,数据存储为 utf-8,调用 win32api 前就不可避免的要转换一次才可以使用,这岂不是又成了“自找不痛快”?

[此贴子已经被作者于2022-11-17 18:23编辑过]

#6
吹水佬2022-11-17 19:28
windows unicode字符串最常用到的是 WideCharToMultiByte、MultiByteToWideChar,可以 UTF16、UTF8 与 ANSI 互换、获取unicode字符数等
windows 的 unicode字符串 通常是用 0h0000 作结束字,但好多时是同时给出字符串buffer的size。
#7
csyx2022-11-17 21:08
以下是引用吹水佬在2022-11-17 19:28:26的发言:

windows unicode字符串最常用到的是 WideCharToMultiByte、MultiByteToWideChar,可以 UTF16、UTF8 与 ANSI 互换、获取unicode字符数等
windows 的 unicode字符串 通常是用 0h0000 作结束字,但好多时是同时给出字符串buffer的size。

这就没意思了,如果仅为了计算unicode字符串的长度,还不如直接调用lstrlen这个api,甚至直接调用C函数库的wcslen来得更直接,又何必依赖编码转换这一对函数的副产品。但是追根究底,底层必须有支持计算字符串长度的算法,除非有一条机器指令可以完成这件事。没人会认为变长字节的编码会比定长字节编码更容易处理吧?
我只是对楼主提出的“遇到Unicode字符,应尽量地转换至UTF-8来处理”这点提出置疑。排除 web 应用,对 WinForm 的 unicode 应用来说,我认为 utf-16 就比 utf-8 更合适

其实在 vfp 板块谈论处理 unicode 本身就是费力不讨好的事,工欲善其事必先利其器,大把原生支持 unicode 的语言,咱又何必费那事儿!
#8
倦猫19732022-11-17 21:37
其实从名字就应该看得出来是什么意思了。一夜之间全面转投 unicode 是不现实的估计全世界都疯了,因此需要一个阶段慢慢平滑过渡。就以记事本为例吧,xp 还有 BOM 头,Win10 下就己经没了。
#9
cssnet2022-11-17 21:38
以下是引用csyx在2022-11-17 18:18:40的发言:
用 vfp 代码实现原生函数 LenC 的 unicode 版,分别用 utf-8 和 utf-16 作为输入参数测试一下,哪种编码格式更有优势?要在 vfp 端处理 unicode 字符,有很大可能需要自己来实现这些功能


实战中,我比较偷懒,一般直接调用C库函数来处理Unicode字符。
至于传递参数,那当然是转为UTF-8更安全、更优胜!
具体到你提及的uniLenC()函数,我查了一下函数库,C实现非常简单,只是一个静态查找表和一个宏:
//-----------------------------
//定义查找表,长度256,表中的数值表示以此为起始字节的utf8字符长度
static uchar utable[] =
{
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
};
#define Ulength(x) utable[(x)]
//-----------------------------
这个C实现,可直接翻译成VFP原生代码,无任何问题的。

utf-8编码最诱人的好处是:绝不会让你遇上?? —— 但凡用VFP处理过Unicode字符的同学,相信能够明白我说的是什么。只要你传递的参数是utf-8,无论是传入还是传出,都不必担心??问题。
#10
吹水佬2022-11-17 23:36
回复 7楼 csyx
WideCharToMultiByte、MultiByteToWideChar 主要是用来互相转换,同时也能返回字数,注意,是字数,不是字节数。
通式的话,就算返回给你UTF8的字数,字节数也不好猜测,只求长度什么API都不用吧。
#11
csyx2022-11-18 01:19
以下是引用吹水佬在2022-11-17 23:36:48的发言:

WideCharToMultiByte、MultiByteToWideChar 主要是用来互相转换,同时也能返回字数,注意,是字数,不是字节数。
通式的话,就算返回给你UTF8的字数,字节数也不好猜测,只求长度什么API都不用吧。

我说的也是字符数而非字节数,字节数谁都会数数
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录
#12
吹水佬2022-11-18 07:52
回复 11楼 csyx
就是了
还是回到VFP的问题,VFP没有“字”的概念,顶多也是双字节、宽字符。W带头的通常也是指“宽字符”,所以VFP调用W***()通常要用到STRCONV(...,5)。
VFP提到的UNICODE也只有局限到一些,至于UNICODE的“字”,通常有8bit、16bit、24bit、32bit、40bit、48bit...甚至更多bit。
VFP如何精准获取UNICODE字符串,尤其是从文件中获取,甚至在超大文件中获取,通常是要通过缓冲来处理。

#13
cssnet2022-11-18 09:11
严格说来,utf-16其实是不定长的。在Unicode基本平面定义的字符,没错儿是2字节;而在辅助平面定义的字符,则为两个2字节(即4字节)。
故而,若追求定长,那必须是UTF-32,每个字符都使用4字节。当然那样一来,存储英文的磁盘空间,就多了三倍。存储中文,也比ANSI多了将近1倍。
不能因为Windows API是utf-16,就说它好啊。
USC-2我也觉得爽哇!偷懒时当然我也曾这么干:

LenByte = len(c)
LenUnicode = int(LenByte/2)
假装Unicde == USC-2,假装用户不可能用到辅助平面定义的字符。

只是,在VFP这种ANSI内核的环境之下,若需处理Unicode,那么,转换成UTF-8,可能是最优、最安全的方案,没有之一。
1