AWTK 中的字符串编码

1. 背景

不少同学在使用 AWTK 的过程中,遇到过字符串编码的问题。这里介绍一下 AWTK 中的字符串编码,希望能让新手少走弯路。

AWTK 中的字符串都是 Unicode 的,但是会使用两种不同的编码:

  • UTF-8 其字符串类型为 char*。
  • UTF-32 其字符串类型为 wchar_t*。

使用场景如下:

  • 不需要显示的字符串使用 UTF-8 编码。如控件名、属性名、资源名和文件名等等。

  • 需要显示的字符串(也就是控件的文本)使用 UTF-32 编码。如按钮上的文本和编辑器中的文本等等。

UTF-8 的好处是能够兼容 ASCII,一般字符串操作比较方便。但是在编辑和显示文本时,需要把字符解码出来,使用不方便而且影响性能,所以 AWTK 中需要显示的字符串使用了 UTF-32 编码。

2. 源文件的编码

AWTK 的源文件,不管是 AWTK 本身还是应用程序,源文件一定要使用 UTF-8 BOM 格式。如果文件头有 UTF-8 BOM(Byte Order Mark) ,明确告诉编译器源文件的编码格式。否则不同的编译器可能有不同的解释,导致显示出现乱码。

最好是不要在源文件中使用非 ASCII 字符串,把界面上要显示的文本全部放到字符串资源文件中。可以避免不少问题,后期支持国际化也非常方便。

好像也有非主流编译器不支持 UTF-8 BOM 格式的源文件。AWTK 也提供了一个工具,用来去掉 UTF-8 BOM,在这个目录下:tools/remove_utf8_bom。

3. 用 UTF-8 的方式设置控件文本

用 widget_set_text_utf8 设置控件文本,其函数原型如下:

/*** @method widget_set_text_utf8* 设置控件的文本。* 只是对 widget\_set\_prop 的包装,文本的意义由子类控件决定。* @annotation ["scriptable"]* @alias set_text* @param {widget_t*} widget 控件对象。* @param {const char*}  text 文本。** @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。*/ret_t widget_set_text_utf8(widget_t* widget, const char* text);

要注意的是:这里的 text 一定要是有效的 UTF-8 编码的字符串。常见的错误有两种:

  • 把 GBK 等编码直接当作 UTF-8 编码使用。
  • 使用了 UTF-8 编码,但是最后一个字符非正常截断(使用 strncpy/snprintf 等函数时,如果目标内存不够大,可能会出现)。

这两种情况都可能导致下面的 assert:

libunibreak/linebreak.c:799: set_linebreaks: Assertion `posLast == posCur - 1 && posCur <= len' failed.

解决方法如下:

  • 对于 GBK 编码,需要转换后,才能设置到控件中。AWTK 提供了转函数:

请包含下列头文件(嵌入式系统需要自己加入相关源码和数据)。

charset/encoding.h
/*** @method encoding_convert** 字符集转换。** @annotation ["static"]** @param {encoding_name_t} from 源字符串的编码名称。* @param {const char*} from_str 源字符串。* @param {uint32_t} from_size 源字符串的长度。* @param {encoding_name_t} to 目标字符串的编码名称。* @param {const char*} to_str 目标字符串。* @param {uint32_t} to_size 目标字符串的最大长度。** @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。*/
ret_t encoding_convert(encoding_name_t from, const char* from_str, uint32_t from_size,encoding_name_t to, char* to_str, uint32_t to_size);/*** @method encoding_gbk_to_utf8** 将 gbk 转换成 utf8 编码。** @annotation ["static"]** @param {const char*} from_str 源字符串 (gbk)。* @param {uint32_t} from_size 源字符串的长度。* @param {const char*} to_str 目标字符串 (utf8)。* @param {uint32_t} to_size 目标字符串的最大长度。** @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。*/
ret_t encoding_gbk_to_utf8(const char* from_str, uint32_t from_size, char* to_str,uint32_t to_size);
  • 对于非正常截断的字符串。最好是分配更大的内存,防止字符串被意外截断。另外,AWTK 提供了一个函数,用来移除最后一个无效字符串。
/*** @method tk_utf8_trim_invalid_char** 如果字符串最后一个字符串是无效的,删掉该无效字符。** > 对于用 strncpy/snprintf 等生成字符串时,如果目标字符串内存大小不够,* > 可能最后一个字符被从中间截断,导致该字符是无效的,这可能会触发 assert,* > 本函数可以用来删除最后一个无效字符。** @param {const char*} str 输入字符串。** @return {char*} 返回 UTF8 字符串。*/
char* tk_utf8_trim_invalid_char(char* str);

4. 用 UTF-8 的方式获取控件文本

用 widget_get_text_utf8 可获取控件的文本,其格式为 UTF-8 格式的字符串。

/*** @method widget_get_text_utf8* 获取控件的文本。* 只是对 widget\_get\_prop 的包装,文本的意义由子类控件决定。* @param {widget_t*} widget 控件对象。* @param {char*}  text 用于返回文本。* @param {uint32_t} size text 内存长度。** @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。*/
ret_t widget_get_text_utf8(widget_t* widget, char* text, uint32_t size);

这个要注意的是 text 的内存要够大,否则可能触发 assert。

5. 用 UTF-32 的方式设置控件文本

用 widget_set_text 设置控件的文本,其原型如下:

/*** @method widget_set_text* 设置控件的文本。* 只是对 widget\_set\_prop 的包装,文本的意义由子类控件决定。* @param {widget_t*} widget 控件对象。* @param {const wchar_t*}  text 文本。** @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。*/
ret_t widget_set_text(widget_t* widget, const wchar_t* text);

如果直接设置常量字符串,字符串一定要加 L 前缀。L 是告诉编译器使用 UTF-32 格式的字符串,否则可能编译出错,或者显示乱码(如果忽略警告)。

widget_set_text(button, L"文本");

6. 用 UTF-32 的方式获取控件文本

用 widget_get_text 获取控件文本,其原型如下:

/*** @method widget_get_text* 获取控件的文本。* 只是对 widget\_get\_prop 的包装,文本的意义由子类控件决定。** 如果希望获取 UTF8 格式的文本,可以参考下面的代码:** ```c*  str_t str;*  str_init(&str, 0);*  str_from_wstr(&str, widget_get_text(target));*  log_debug("%s: %s\n", target->name, str.str);*  str_reset(&str);* ```** @annotation ["scriptable"]* @param {widget_t*} widget 控件对象。** @return {const wchar_t*} 返回文本。*/
const wchar_t* widget_get_text(widget_t* widget);

AWTK 中的字符串编码相关推荐

  1. java中改变字符串编码

    经常因为字符编码的问题而去网上搜一些改变字符编码的东西,很麻烦,这次总结了一下比较全的改变字符编码的方法以供参考.代码如下: 代码块 import java.io.UnsupportedEncodin ...

  2. python中对字符串进行编码_Python 中的字符串编码

    对Python字符编码一直没搞明白,今天看<Python参考手册>再次遇到这个问题,重新整理下 Python中字符串字面量用于指定一个字符序列,其定义方法是把文本放入单引号('),双引号( ...

  3. javascript中的字符串编码、字符串方法详解

    js中的字符串是一种类数组,采用UTF-16编码的Unicode字符集,意味字符串的每个字符可用下标方式获取,而每个字符串在内存中都是一个16位值组成的序列.js对字符串的各项操作均是在对16位值进行 ...

  4. python2和python3的默认编码_Python2和Python3中的字符串编码问题解决

    原博文 2018-01-02 11:38 − Python2和Python3在字符串编码上是有明显的区别. 在Python2中,字符串无法完全地支持国际字符集和Unicode编码.为了解决这种限制,P ...

  5. 关于python中的字符串编码理解

    python2.x 中中间编码为unicode,一个字符串需要decode为unicode,再encode为其它编码格式(gbk.utf8等) 以gbk转utf8为例: s = "我是字符串 ...

  6. python2中的字符串编码注意事项

    1.不同编码之间进行转换的桥梁是最上层的字符集. 2.python2的字符本质是一种二进制码. python环境下: 如图所示: >>> s = "你好" > ...

  7. 韩文编码python_python中的字符串编码问题——4.unicode编解码(以实际工作中遇到的韩文编码为例)...

    韩文unicode编解码 问题是这样,工作中遇到有韩文数据出现乱码,说是unicode码. 类似这样: id name323 52186863 149 63637538 314 65516863 32 ...

  8. python字符串编码及乱码解决方案

    http://blog.csdn.net/pipisorry/article/details/44136297 字符编码详解 [字符编码ASCII,Unicode和UTF-8] 主要非英文字符集的编码 ...

  9. python3中字符串编码常见种类_Python基础篇—标准数据类型—String字符串编码问题...

    我要开始写String编码问题了...脑壳疼.. 在String字符串的第一篇末尾有留一个坑,就是关于中文字符串编码.整个编码的故事说起来都是很费劲的,我也只能把我所知道的梳理整理一下,在日常敲码过程 ...

最新文章

  1. 理解模板引擎Razor 的原理
  2. mybaits二十四:缓存原理示意图
  3. Alibaba-Dexposed框架在线热补丁修复的使用
  4. Bigpipe---FaceBook使用的页面加载技术
  5. 答读者问:学历不高,要如何破局?
  6. 递归算法思路以及题目总结(未完待续...)
  7. ListView列表刷新方法的区别
  8. 浅谈动态规划和分治、贪心算法的区别
  9. 读《富爸爸,穷爸爸》后感(四)
  10. 微机——微型计算机系统组成及工作原理
  11. Java 使用 iText5 API 根据需求导出 PDF
  12. ThinkPad E450(c)添加或者更换内存条的一些问题
  13. Kubernetes 1.25 发布!博云带你玩转新特性
  14. 总结最近遇到的几个问题
  15. java计算器rmi_用RMI计算Pi
  16. 为什么网络掩码一定是255.255.255.0(/24)
  17. 加快区块链建设!这所一流大学成立了实验室
  18. 并行计算复习————第一篇 并行计算硬件平台:并行计算机
  19. EasyClick iOS脚本_免越狱_免硬件_iOS杀进程保活方案
  20. 打不赢,就封号!孙杨上诉翻案率仅约7%?

热门文章

  1. 图像分割方法:理论+代码时间
  2. echarts 地图3d+地图下钻
  3. uni-app开发android应用流程
  4. 弘辽科技:淘宝直通车出价的技巧汇总
  5. 【使用SheetJS实现在网页端导出 Excel 表格保存(js-xlsx)】
  6. Python制作gif动图(PIL)
  7. Win10升级后极速模式网页打开卡慢的解决办法
  8. Photoshop for Designers: Filters 适用于设计师的Photoshop:滤镜 Lynda课程中文字幕
  9. Android开发: 分享利用好Kotlin的特点提高开发效率
  10. 解决内存不能为Read问题