【问题标题】:How to know the number of characters in utf8 string如何知道utf8字符串中的字符数
【发布时间】:2011-10-29 19:27:17
【问题描述】:

我想知道有没有一种简单的方法来确定UTF8 字符串中的字符数。 例如,在 windows 中可以通过以下方式完成:

  1. UTF8 字符串转换为wchar_t 字符串
  2. 使用wcslen函数并得到结果

但我需要更简单和跨平台的解决方案。

提前致谢。

【问题讨论】:

  • 使用跨平台库。像重症监护室。注意字符(由 wcslen 返回)和代码点之间的区别。
  • 我需要一个函数,它会给我 UTF8 字符串的长度,所以我认为添加整个库以仅使用一个函数并不是一个好主意。
  • 那么,复制粘贴代码。它是开源的,您可以随心所欲地使用它。我怀疑你会喜欢跨平台做事所需的典型宏汤。
  • 您是否考虑过使用提供强大 Unicode 支持的语言和/或库?自己动手似乎是灾难的根源。
  • @tchrist,不,我假设所有传入路径都将采用 UTF8 格式,并且在库中我使用字符串函数(c 中的 string.h)来操作这些路径。我要检查的一件事是路径的长度。这就是我问这个问题的原因。我的方法是正确的还是有更好的解决方案请告诉我。

标签: c string utf-8 character-encoding


【解决方案1】:

UTF-8 字符要么是最左位为0 的单个字节,要么是第一个字节的最左位为1..10... 的多个字节(左侧的 1 的数量为 2 或更多)后跟10... 形式的连续字节(即左侧的单个1)。假设您的字符串格式正确,您可以遍历所有字节并在每次看到不格式为 10... 的字节时增加“字符数” - 即仅计算所有 UTF-8 字符中的第一个字节.

【讨论】:

  • 好主意!谢谢;)。但这是唯一的方法吗?
  • @akmal - 我确信有替代解决方案,但这很简单,而且可以按要求跨平台。您标记了问题 C 和原始 C 标准比 unicode 标准早了几年。因此,在所有 C 版本中都没有适用于 unicode 的内置 C 函数。
  • 您的解决方案对我来说有点令人困惑..您是在谈论 BOM 吗?如果不是,您无法推断出一个字符是否占用 1、2 或更多字节……而且……您的字节和最左边字节的内容更加令人困惑……1 字节 = 8 位,对吗?跨度>
  • @duedl0r - UTF-8 序列的第一个字节(8 位)告诉您整个序列中的字节数。因此,通过仅计算这些字节,您可以知道流中的字符数(字符而不是字节)。
  • @borrible:这对我来说听起来很奇怪,第一个字节中序列的字节数???你有支持这种说法的链接吗?
【解决方案2】:

“字符数”的整个概念并不真正适用于 Unicode,因为代码不会 1:1 映射到字形。如果您想以未压缩的形式建立存储需求,@borrible 提出的方法很好,但它可以告诉您的仅此而已。

例如,有像“零宽度空间”这样的代码点,在渲染时不占用屏幕上的空间,而是占用一个代码点,或者是变音符号或元音的修饰符。因此,任何统计数据都必须针对具体应用。

一个适当的 Unicode 渲染器将具有一个函数,如果该信息是您所追求的,该函数可以告诉您将使用多少像素来渲染字符串。

【讨论】:

  • 我将使用这个函数来确定路径长度是否正确。我假设 Windows 中可能的路径长度是 MAX_PATH 字符(不是字节),在 linux PATH_MAX 字符上,它是否正确?
  • @akmal:在“未压缩形式的存储要求”标题下,因为 Windows 文件名不关心字符组合甚至代理对,它实际上只是一系列 16 位价值观。但请注意,如果您的 UTF-8 输入中有 BMP 之外的字符,那么 MAX_PATH Unicode 代码点将转换为超过 MAX_PATH TCHAR “字符”。 Posix PATH_MAX 是字符(字节)的数量,而不是任何类型的 Unicode 字符的数量。
  • 如果您这样做是为了检查路径长度,我不确定这是一个好主意。 PATH_MAX 的唯一目的是确保内核不必处理无限大的路径搜索,这可能是 DoS 攻击。与其尝试在应用程序中强制执行PATH_MAX,不如让内核拒绝它不喜欢的路径??
  • Wrt PATH_MAX 问题,另请参阅stackoverflow.com/questions/7106911/…(由同一用户显示)。
  • @R.. 好吧,但它会正常工作吗,例如,如果路径长度约为 500 个字符,而 MAX_PATH(在 Windows 中)为 260 个字符。
【解决方案3】:

如果已知字符串是有效的 UTF-8,则只需以字节为单位获取字符串的长度,不包括值在 0x80-0xbf 范围内的字节:

size_t i, cnt;
for (cnt=i=0; s[i]; i++) if (s[i]<0x80 || s[i]>0xbf) cnt++;

请注意,s 必须指向 unsigned char 的数组才能进行比较。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-13
    • 2013-08-20
    • 2012-07-17
    • 2023-03-23
    • 1970-01-01
    • 2011-11-02
    • 2011-05-28
    • 1970-01-01
    相关资源
    最近更新 更多