← 返回信息流
AI 资讯Hacker News·2 小时前

开发者发布Mojibake:基于C的底层Unicode库

原标题:Show HN: Mojibake – a low-level Unicode library written in C

速览

Mojibake是一个用C实现的底层Unicode库,提供低级别文本编码转换功能。该库针对性能优化,适合嵌入系统或对资源敏感的场景。它为开发者提供了更灵活的字符处理方案,有助于在多语言环境下简化编码问题。

AI 深度解读

背景

在软件开发中,Unicode 处理是一个常见但复杂的任务。无论是文本规范化、大小写转换、字符分割还是排序比较,都需要对 Unicode 标准有深入的理解和实现。现有的 Unicode 库(如 ICU、libunistring 等)功能强大但往往体积庞大、依赖较多,对于嵌入式或对二进制大小敏感的项目不够友好。Mojibake 正是为了解决这一问题而诞生的:一个用 C11 编写、兼容 C++17 的底层 Unicode 17 文本处理库,遵循 MIT 许可证,力求小巧、易用、快速且自包含。

核心内容

Mojibake 是一个低层级(low-level)的 Unicode 文本处理库,仅需两个文件(mojibake.cmojibake.h)即可集成到 C/C++ 项目中,零依赖。它实现了 Unicode 17.0.0 标准所规定的全部算法,并通过官方测试套件。

使用方法

无需安装,只需将头文件和源文件添加到项目中。以下是示例代码演示了三种功能:

  1. 规范化(Normalization):将 "Cafe\xCC\x81"(即 "Cafe" 后跟一个 U+0301 COMBINING ACUTE ACCENT)通过 NFC 规范化为 "Café"(U+00E9),输出如下:
    Cafe<CC><81>
    Caf<C3><A9>
    
  2. 字符计数:对字符串 "文字化け"(UTF-8 长度 12 字节)使用 mjb_string_length 得到正确的字符数 4。
  3. NFKC Casefold:将 "Straße" 通过 NFKC casefold 转换为 "strasse"(ß → ss),输出:
    Straße -> strasse
    

功能亮点

所有 C 文件与 Unicode 数据表合并为一个大文件(mojibake.cmojibake.h),零外部依赖。

文本转换

  • 规范化:NFC/NFD/NFKC/NFKD(mjb_normalize),面向标识符的 NFKC case folding(mjb_nfkc_casefold),以及快速 quick-check(mjb_string_is_normalized)。遵循 UAX #15,Unicode 17.0.0。
  • 大小写转换:大写、小写、标题大小写、case folding,支持完整的特殊大小写和条件映射(mjb_case)。
  • 过滤:在规范化的同时去除控制字符、空格或数字(mjb_string_filter)。

文本分析

  • 字符数据库:获取每个 Unicode 字符的 UCD 属性:类别(category)、文字(script)与脚本扩展(Script_Extensions)、区块(block)、平面(plane)、数值、名称(mjb_codepoint_charactermjb_codepoint_script_extensions)。
  • 分割:字素簇(grapheme clusters)、单词、句子、断行机会(UAX #29 和 UAX #14,Unicode 17.0.0)。
  • 双向文本:完整 Unicode 双向算法:段落解析、行重排序、运行(run)(UAX #9,Unicode 17.0.0)。
  • Emoji:码点属性、序列分析、RGI emoji 检测。
  • 显示宽度:东亚宽度和终端显示宽度,支持宽度感知截断(mjb_display_widthmjb_truncate_width)。

排序与比较

  • 排序(Collation):Unicode Collation Algorithm(UCA)字符串比较和排序键,支持 shifted 和 non-ignorable 模式(mjb_string_comparemjb_collation_key,UTS #10,Unicode 17.0.0)。

安全

  • 混淆检测:生成可复用的骨架(skeleton)并检查字符串是否视觉混淆(mjb_confusable_skeletonmjb_string_is_confusable,UTS #39,Unicode 17.0.0)。
  • 标识符验证:XID/ID 检查,面向解析器和编译器作者(mjb_string_is_identifier,UAX #31,Unicode 17.0.0)。

集成

  • 编码:API 接受并输出 UTF-8、UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE 字符串,具有编码检测和转换功能(mjb_string_encodingmjb_string_convert_encoding)。
  • 解析与字符串函数:逐字符迭代(mjb_next_character)和标准 <string.h> 风格的辅助函数(mjb_string_length 等)。
  • 区域设置:严格的 BCP 47 语言标签解析(mjb_locale_parse)。
  • 可嵌入性:自定义分配器(mjb_set_memory_functions)、编译时功能标志以缩减数据表大小、C++17 包装器(src/cpp/mojibake.hpp)、CLI 工具(src/shell)、WASM + TypeScript API(src/api)。
  • 测试与模糊测试:使用 Attractor 测试套件运行超过 150 万条断言,涵盖官方 Unicode 一致性测试;使用 libFuzzer 对不可信字节输入进行模糊测试,并且通过了 AddressSanitizer 和 UBSan 检测。

编译时特性

Mojibake 可以通过宏控制编译哪些可选特性表,以减小二进制体积。例如,#define MJB_FEATURE_CHARACTER_NAMES 控制字符名称表,禁用后输出大小减少约 30%,字符名称会显示为 "Codepoint U+XXXX"。可通过 CMake 或 Makefile 设置。

CLI 工具

src/shell 目录编译出 mojibake 命令行工具,用于测试。示例:

# 输出 "NFC: Café"
mojibake nfc $'Cafe\u0301'
# 输出 emoji 序列信息
mojibake emoji "☺️"

许可

MIT 许可证。Unicode 字符数据库和 CLDR 数据版权归 Unicode, Inc. 所有。

关键要点

  • 完全符合 Unicode 17.0.0:实现了 UAX #9、#14、#15、#29、#31,UTS #10、#39 等标准中的所有算法,并通过官方测试套件。
  • 零依赖自包含:仅两个文件(mojibake.cmojibake.h),所有 Unicode 数据表已整合,无需外部库或数据文件。
  • 跨平台:支持 Linux、macOS、FreeBSD、OpenBSD、NetBSD、Windows 10/11。
  • 多种编码支持:原生支持 UTF-8、UTF-16LE/BE、UTF-32LE/BE,并包含编码检测和转换。
  • 功能全面:覆盖规范化、大小写转换、字符属性查询、文本分割、双向文本、Emoji 检测、显示宽度、排序、混淆检测、标识符验证等常见 Unicode 处理需求。
  • 可定制体积:通过编译时宏可以禁用可选特性(如字符名称表),以减小二进制大小,适合资源受限环境。
  • 安全可靠:经过模糊测试、AddressSanitizer 和 UBSan 清理,并运行 150 万+ 断言。
  • 易于集成:提供 C 直接使用、C++17 包装器、CLI 工具以及 WASM + TypeScript API,满足多种使用场景。
  • 自定义分配器:可通过 mjb_set_memory_functions 控制内存管理,适合嵌入式和性能关键应用。

意义与影响

Mojibake 的出现填补了现有 Unicode 处理库的两个空白:一方面,它比 ICU 等项目更轻量、更易于集成,适合那些不希望引入庞大依赖的 C/C++ 项目;另一方面,它保持了与 Unicode 标准的严格一致性,避免了民间实现中

查看原文 →mojibake.zaerl.com