当前位置: 首页 > wzjs >正文

wap网站设计seo公司服务

wap网站设计,seo公司服务,seo公司哪家好咨询,wordpress食谱门户给你这样一个需求:实现一个函数,我们将用这个函数来计算用户在注册账号时输入的用户名长度,当用户名长度超过限制5时,我们会阻止用户使用这个用户名。函数输入为UTF-8编码的std::string。 这听起来似乎很容易,一行代码…

给你这样一个需求:实现一个函数,我们将用这个函数来计算用户在注册账号时输入的用户名长度,当用户名长度超过限制5时,我们会阻止用户使用这个用户名。函数输入为UTF-8编码的std::string

这听起来似乎很容易,一行代码就能够搞定:

int stringLength(const std::string& s) { return s.size(); }

注册我们账号的第一位用户叫做Mary,stringLength不负众望地给我们返回了4,这让她通过了用户名长度检测,顺利注册了账号。

第二位用户叫做东方不败,他的名字看起来也只有4个字,应该也能够顺利通过用户名长度检测。然而事与愿违,用户界面提示用户名超长,通过一番调试,我们发现stringLength返回了12。

虽然初看起来有点奇怪,但是作为一个程序员,经过短暂的思考以后,我们不难弄清楚,一个英文字母和一个汉字虽然都对应一个Unicode code point,但是在使用UTF-8编码时,英文字母和汉字由于code point的范围不同,它们的“地位”是不同的。

First code pointLast code pointByte 1Byte 2Byte 3Byte 4
U+0000U+007F0yyyzzzz
U+0080U+07FF110xxxyy10yyzzzz
U+0800U+FFFF1110wwww10xxxxyy10yyzzzz
U+010000U+10FFFF11110uvv10vvwwww10xxxxyy10yyzzzz

之所以会得到12,是因为常用汉字的Unicode Block “CJK Unified Ideographs” code point范围为U+4E00~U+9FFF,使用UTF-8编码时占3个字节,3x4=12:

东方不败
U+4E1C U+65B9 U+4E0D U+8D25
0xE4 0xB8 0x9C 0xE6 0x96 0xB9 0xE4 0xB8 0x8D 0xE8 0xB4 0xA5

但是作为一名对Unicode/UTF-8一窍不通的普通用户,东方不败大概不会满意我们的解释,他只知道自己心爱的名字“东方不败”4个字因为超出长度限制5而无法注册,这太荒谬了。为了让这名用户满意,我们需要实现一个stringLength_v2来纠正这个问题。

stringLength_v2中,std::string::size将派不上用场,它代表的是字符串占用了几个字节,而不是里面有几个文字。由于C++标准库中并没有可靠的Unicode编解码接口,此时我们最好依赖三方库,使用icu将UTF-8编码的std::string转换成icu::UnicodeString,然后“数一数”里面到底有几个code point,按我们目前的理解,一个code point就是一个字,有几个code point就是有几个字。

int stringLength_v2(const std::string& s) {icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(s);int32_t length = 0;for (int32_t i = 0; i < ustr.length();) {UChar32 c;U16_NEXT(ustr.getBuffer(), i, ustr.length(), c);if (c >= 0) {++length;}}return length;
}

需要注意的是,icu::UnicodeString内部使用UTF-16存储数据,因此ustr.length()并不是code point的个数,我们必须自己来数。

将“东方不败”4个字传给stringLength_v2以后,我们如愿得到了4,用户东方不败也顺利注册了自己的账号。

又来了一位用户,他的名字叫做 👨‍👩‍👧‍👦,你不要觉得奇怪,这个世界发展很快,也许以后每个人都会把emoji放进自己的名字,毕竟emoji也是Unicode,而且还是很酷的Unicode。这个用户名看起来只有一个“字”,但他也没能顺利地通过用户名长度检测,我们惊奇地发现,stringLength_v2给我们返回了7。

这次又是哪里弄错了呢?stringLength_v2数出来有7个code point,但是这个用户的名字看起来只有一个“字”。把7个code point都打印出来,它们分别是:

👨‍👩‍👧‍👦
U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466

他的名字确实有7个code point,但显示时又只占据了一个字符的空间。经过一番学习,我们又了解到了grapheme cluster和combining character的概念,简而言之,用户看到的一个“字”,并不对应着一个code point,而是对应着一个grapheme cluster。而一个grapheme cluster可能是由多个code point组成的。除了emoji,还有下面这些例子,它们都是包含combining character的grapheme cluster,我们可以使用C++的\u转义来构造它们:

"\u092b\u093f" -> फि
"\u0061\u0308\u0303\u0323\u032d" -> ạ̭̈̃
"\u0e02\u0e36\u0e49" -> ขึ้

为了让用户👨‍👩‍👧‍👦能够顺利注册账号,我们需要再实现一个stringLength_v3,这个版本不再计算code point的个数,而是计算grapheme cluster的个数,它才是用户看到的字符的个数。

int stringLength_v3(const std::string& s) {UErrorCode status = U_ZERO_ERROR;icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(s);std::unique_ptr<icu::BreakIterator> bi(icu::BreakIterator::createCharacterInstance(icu::Locale::getDefault(),status));if (U_FAILURE(status) || !bi) {return -1;}bi->setText(ustr);int count = 0;for (int32_t start = bi->first(), end = bi->next();end != icu::BreakIterator::DONE; start = end, end = bi->next()) {++count;}return count;
}

stringLength_v3的帮助下,用户👨‍👩‍👧‍👦成功注册了账号,他对stringLength_v3表示了感谢。不过需要注意的是,Unicode并没有规定一个grapheme cluster中code point数量的上限,恶意用户完全可以构造一个超长的单一grapheme cluster来消耗我们宝贵的资源,因此有必要为s.size()也加上一个限制,比如说64。如果真的有善良的用户通过了stringLength_v3考验,但是没能通过s.size()的考验,我们可以考虑把他介绍给我们的竞争对手,他们拥有丰富的资源。

stringLength_v3让所有用户顺利注册了账号,皆大欢喜的结局!


一些有用的URL:

  1. https://www.compart.com/en/unicode/plane/U+0000: 拥有整套的Unicode数据集,可以让你获取到每个Unicode code point你想了解的所有信息
  2. https://www.compart.com/en/unicode/block/U+4E00: Unicode Block “CJK Unified Ideographs”
  3. https://home.unicode.org/: Unicode官网
  4. https://www.unicode.org/versions/latest/: Unicode标准最新版本
  5. https://unicode.org/emoji/charts/full-emoji-list.html: Emoji全集
  6. https://icu.unicode.org/: icu官网
  7. https://en.wikipedia.org/wiki/Unicode: Unicode维基百科
  8. https://en.wikipedia.org/wiki/UTF-8: UTF-8维基百科

最后附上完整的代码和输出。

代码

#include <unicode/brkiter.h>
#include <unicode/locid.h>
#include <unicode/unistr.h>
#include <unicode/utypes.h>#include <iostream>
#include <string>
#include <vector>int stringLength(const std::string& s) { return s.size(); }int stringLength_v2(const std::string& s) {icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(s);int32_t length = 0;for (int32_t i = 0; i < ustr.length();) {UChar32 c;U16_NEXT(ustr.getBuffer(), i, ustr.length(), c);if (c >= 0) {++length;}}return length;
}int stringLength_v3(const std::string& s) {UErrorCode status = U_ZERO_ERROR;icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(s);std::unique_ptr<icu::BreakIterator> bi(icu::BreakIterator::createCharacterInstance(icu::Locale::getDefault(),status));if (U_FAILURE(status) || !bi) {return -1;}bi->setText(ustr);int count = 0;for (int32_t start = bi->first(), end = bi->next();end != icu::BreakIterator::DONE; start = end, end = bi->next()) {++count;}return count;
}int main() {std::vector<std::string> names = {"Mary","东方不败","👨‍👩‍👧‍👦","\u0061\u0308\u0303\u0323\u032d","\u0e02\u0e36\u0e49","\u092b\u093f"};for (const std::string& name : names) {printf("%2d %2d %2d %s\n", stringLength(name), stringLength_v2(name),stringLength_v3(name), name.c_str());}return 0;
}

编译

g++ -licuuc main.cpp

输出

 4  4  4 Mary
12  4  4 东方不败
25  7  1 👨‍👩‍👧‍👦9  5  1 ạ̭̈̃9  3  1 ขึ้6  2  1 फि
http://www.dtcms.com/wzjs/56270.html

相关文章:

  • 上海网站建设基础舆情监控
  • 58桐城网站做装修推广是真的吗新闻式软文经典案例
  • 新乡网站推广福州百度推广优化排名
  • 新疆网站党建设备福州网seo
  • 海口网站建设哪家好郑州seo询搜点网络效果佳
  • wordpress 图片拉伸知乎seo优化
  • 建筑公司网站案例营销排名seo
  • 天津网站在哪里建设百度一下你就知道了主页
  • 网站管理运营如何免费开自己的网站
  • 中国建设银行网站开通短信服务东莞seo推广公司
  • 佛山正规网站建设报价各大引擎搜索入口
  • 有经验的合肥网站建设刷关键词排名系统
  • 外贸网站建设费用一般要多少全媒体运营师报名入口
  • 高端产品网站建设网页模板大全
  • 杭州餐饮团购网站建设企业网站优化外包
  • 石柱网站制作自媒体发稿
  • 网站运营方案设计编程培训机构排名前十
  • 公司网站建设佛山哪家好吸引客人的产品宣传句子
  • 陕西做网站公司哪家好百度网盘网址
  • html中音乐网站怎么做永久不收费免费的聊天软件
  • 建网站被封了营销网站建设培训学校
  • 中企动力网站建设公司seo优化在线
  • 建设手机网站费用seo网上培训课程
  • 好企业网站河南郑州最近的热搜事件
  • wordpress无法显示图片广州seo优化电话
  • 贵州西能电力建设有限公司网站百度seo排名优化公司推荐
  • 三亚高端服务网站成品短视频app下载有哪些
  • 盗版做的最好的网站新网站seo外包
  • 广州英铭网站建设网站建设公司排名
  • wix网站做图片能折叠吗水果店推广营销方案