如何在纯 C 中检测 UTF-8?

2023-11-25

我正在寻找一个普通旧 C 代码片段,它检测给定的字符串是否采用 UTF-8 编码。我知道使用正则表达式的解决方案,但由于各种原因,在这种特殊情况下最好避免使用除纯 C 之外的任何内容。

使用正则表达式的解决方案如下所示(警告:省略了各种检查):

#define UTF8_DETECT_REGEXP  "^([\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$"

const char *error;
int         error_off;
int         rc;
int         vect[100];

utf8_re = pcre_compile(UTF8_DETECT_REGEXP, PCRE_CASELESS, &error, &error_off, NULL);
utf8_pe = pcre_study(utf8_re, 0, &error);

rc = pcre_exec(utf8_re, utf8_pe, str, len, 0, 0, vect, sizeof(vect)/sizeof(vect[0]));

if (rc > 0) {
    printf("string is in UTF8\n");
} else {
    printf("string is not in UTF8\n")
}

这是(希望没有错误)的实现这个表达在普通C中:

_Bool is_utf8(const char * string)
{
    if(!string)
        return 0;

    const unsigned char * bytes = (const unsigned char *)string;
    while(*bytes)
    {
        if( (// ASCII
             // use bytes[0] <= 0x7F to allow ASCII control characters
                bytes[0] == 0x09 ||
                bytes[0] == 0x0A ||
                bytes[0] == 0x0D ||
                (0x20 <= bytes[0] && bytes[0] <= 0x7E)
            )
        ) {
            bytes += 1;
            continue;
        }

        if( (// non-overlong 2-byte
                (0xC2 <= bytes[0] && bytes[0] <= 0xDF) &&
                (0x80 <= bytes[1] && bytes[1] <= 0xBF)
            )
        ) {
            bytes += 2;
            continue;
        }

        if( (// excluding overlongs
                bytes[0] == 0xE0 &&
                (0xA0 <= bytes[1] && bytes[1] <= 0xBF) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF)
            ) ||
            (// straight 3-byte
                ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) ||
                    bytes[0] == 0xEE ||
                    bytes[0] == 0xEF) &&
                (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF)
            ) ||
            (// excluding surrogates
                bytes[0] == 0xED &&
                (0x80 <= bytes[1] && bytes[1] <= 0x9F) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF)
            )
        ) {
            bytes += 3;
            continue;
        }

        if( (// planes 1-3
                bytes[0] == 0xF0 &&
                (0x90 <= bytes[1] && bytes[1] <= 0xBF) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
                (0x80 <= bytes[3] && bytes[3] <= 0xBF)
            ) ||
            (// planes 4-15
                (0xF1 <= bytes[0] && bytes[0] <= 0xF3) &&
                (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
                (0x80 <= bytes[3] && bytes[3] <= 0xBF)
            ) ||
            (// plane 16
                bytes[0] == 0xF4 &&
                (0x80 <= bytes[1] && bytes[1] <= 0x8F) &&
                (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
                (0x80 <= bytes[3] && bytes[3] <= 0xBF)
            )
        ) {
            bytes += 4;
            continue;
        }

        return 0;
    }

    return 1;
}

请注意,这是 W3C 推荐的用于表单验证的正则表达式的忠实翻译,它确实拒绝一些有效的 UTF-8 序列(特别是包含 ASCII 控制字符的序列)。

此外,即使在通过进行评论中提到的更改来修复此问题之后,它仍然假设零终止,这会阻止嵌入 NUL 字符,尽管它在技术上应该是合法的。

当我涉足创建自己的字符串库时,我使用了修改后的 UTF-8(即将 NUL 编码为超长的两字节序列) - 请随意使用这个标题作为提供验证例程的模板,该例程不会遭受上述缺点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在纯 C 中检测 UTF-8? 的相关文章

  • UTF8/UTF16 和 Base64 在编码方面有什么区别

    In c 我们可以使用下面的类来进行编码 System Text Encoding UTF8 System Text Encoding UTF16 System Text Encoding ASCII 为什么没有System Text En
  • ROWNUM 的 OracleType 是什么

    我试图参数化所有现有的 sql 但以下代码给了我一个问题 command CommandText String Format SELECT FROM 0 WHERE ROWNUM lt maxRecords command CommandT
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • C# 中可空类型是什么?

    当我们必须使用nullable输入 C net 任何人都可以举例说明 可空类型 何时使用可空类型 https web archive org web http broadcast oreilly com 2010 11 understand
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • 我的 strlcpy 版本

    海湾合作委员会 4 4 4 c89 我的程序做了很多字符串处理 我不想使用 strncpy 因为它不会终止 我不能使用 strlcpy 因为它不可移植 只是几个问题 我怎样才能让我的函数正常运行 以确保它完全安全稳定 单元测试 这对于生产来
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var

随机推荐

  • 为什么正则表达式“非捕获”组不起作用?

    在下面的代码片段中 非捕获组 aaa 在匹配结果中应该被忽略 结果应该是 bbb only 但是 我得到 aaa bbb 在匹配结果中 仅当我指定 group 2 时它才会显示 bbb gt gt gt import re gt gt gt
  • 高效的崩溃虚拟变量

    将虚拟变量折叠回因子的有效方法是什么 欢迎任何解决方案 包括非基础包 race White race Hispanic race Black race Asian 1 1 0 0 0 2 0 0 0 1 3 1 0 0 0 4 0 0 1
  • 在 Rmarkdown 中插入带有图像的标题页以呈现 pdf 文档

    在 Rmarkdown 中 以下设置生成 pdf 文档的上下文 title My Report author NDE output pdf document fig caption true toc true highlight kate
  • JSF2 中的 Bean 验证消息和 i18n 如何工作?

    我创建了验证消息 ValidationMessages properties 文件以使 i18n 在我的项目中成为可能 看起来像 pwtNumber error PWT Number error 我在 faces config xml 中定
  • C# CodeDom 自动属性

    我有一个使用 CodeDom 创建的属性 如何将其设置为自动属性 而不是针对私有成员添加 CodeFieldReferenceExpressions IIRC CodeDom 根本没有办法表达这一点 自动实现的属性只是编译器糖 但由于它不能
  • 打印没有字典名称的字典键?如何/为什么?

    所以我创建了一个字典来设置小游戏的难度级别 diff dict easy 0 2 medium 0 1 hard 0 05 difficulty level dict 键将是难度名称和我用来计算难度的一些比率的值 所以我试图弄清楚如何只向用
  • 如何从连接到 PC 的手机发送和读取短信

    我正在构建一个 Windows 桌面软件 它将响应 SMS 请求并自动发送 SMS 作为回复 该软件已准备就绪并且运行良好 但它仅适用于诺基亚手机 前提是必须先安装诺基亚 PC 套件 然后我的应用程序才能运行 但现在我的客户想要更换他的手机
  • Xcode 7.3 自动完成问题

    我对 Xcode 7 3 的新自动完成功能有一些问题 当我导入一个类时 该类不会显示在自动完成中 更烦人的是 当导入的类包含 typedef NS ENUM 时 可能的值也不会显示 在这两种情况下 当我手动输入类名或枚举值时 该特定值将在下
  • 如何从 XSLT 访问 CDATA 中的变量?

    我正在使用 XSLT 转换并需要将一些数据放入CDATA部分并且该值存在于变量中 查询 如何访问变量CDATA 示例如下
  • 让 xargs 对每行输入执行一次命令

    如何使 xargs 对给定的每一行输入精确执行一次命令 它的默认行为是对行进行分块并执行一次命令 将多行传递给每个实例 From http en wikipedia org wiki Xargs 查找 path type f print0
  • JS 中使用 SJCL 以及 Ruby 中使用 OpenSSL 的椭圆曲线加密

    我正在开发一个 Web 应用程序 它必须能够在服务器端使用 ECC 加密数据并在浏览器中解密 我发现在 JS 中唯一能够实现此功能的库是 SJCL 然而 由于 SJCL 中的 ECC 支持目前似乎有点被放弃 所以我使用了fork 它具有密钥
  • pyOpenSSL 创建 pem 文件

    我在 python 中使用以下代码和 pyOpenSSL 创建了一个密钥对 from OpenSSL import crypto k crypto PKey k generate key crypto TYPE RSA 2048 现在如何从
  • Swift 语言中的抽象类

    有没有办法在 Swift 语言中创建抽象类 或者这是像 Objective C 一样的限制吗 我想创建一个与 Java 定义的抽象类相当的抽象类 Swift 中没有抽象类 就像 Objective C 一样 你最好的选择是使用Protoco
  • securesocial 开发时假登录

    我正在使用 securesocial 它工作正常 但现在每次我更改一些 scala 代码时 我都必须再次登录 在开发模式下是否有可能在会话中伪造用户 这样我就不必经常登录 Thanks 乔里斯 韦伦斯 SecureSocial 默认情况下使
  • 将类添加到选择中的选项

    基于选项的值是否可以向选项添加一个类 所以如果我有这个
  • 通过拖放 fullcalendar 更新事件 - Javascript

    我在用着全日历对于我正在开发的项目 我只剩下一个功能需要实现 即将现有事件从其原始位置拖动到另一个时间或日期 我想知道如何获取当前对象信息 标题 新开始时间 旧开始时间 id url 等 以便我可以使用较新的信息更新数据库 Fullcale
  • 为什么 C# 编译器可以“看到”DLL 中未引用的类的静态属性,但看不到实例方法?

    我的问题的前提 用简单的英语来说 一个名为Foo依赖于一个名为的库Bar Foo 中的类扩展了 Bar 中的类 Foo 定义了简单传递给 Bar 的属性 方法 一个应用程序 FooBar 依靠只在 Foo 上 考虑以下示例 class Pr
  • 如何使用常规 makefile 构建依赖于 boost 的项目?

    我正在开发一个c 项目 最近我们需要在其中包含一小部分boost boost 部分确实很小 Boost Python 因此 使用 bjam 构建所有内容看起来有点大材小用 此外 参与该项目的每个人都对 make 感到满意 并且对 jam 不
  • 三元运算符中的多个语句

    在三元运算符语句中包含多个语句的正确语法是什么 str length 1 str str replace 0 str length 00 flag false str str deleteCharAt str length 1 当我的长度达
  • 如何在纯 C 中检测 UTF-8?

    我正在寻找一个普通旧 C 代码片段 它检测给定的字符串是否采用 UTF 8 编码 我知道使用正则表达式的解决方案 但由于各种原因 在这种特殊情况下最好避免使用除纯 C 之外的任何内容 使用正则表达式的解决方案如下所示 警告 省略了各种检查