提升区域设置规范化带状字符,但不规范化重音

Boost locale normalize strips characters but no accents

本文关键字:规范化 字符 区域 设置      更新时间:2023-10-16

我正在尝试使用boost本地库从字符串中删除重音。

规范化功能删除带有重音的整个字符,我只想删除重音。

è -> e 例如

这是我的代码

std::string hello(u8"élève");
boost::locale::generator gen;
std::string str = boost::locale::normalize(hello,boost::locale::norm_nfd,gen(""));

期望输出:eleve

我的输出 : lve

请帮忙

这不是规范化的作用。有了nfd,它就会进行"规范分解"。然后,您需要删除组合字符代码点。

更新从 utf8 表中收集一个松散的实现,大多数组合字符似乎以0xcc或0xcd开头:

活在魔杖盒上

// also liable to strip some greek characters that lead with 0xcd
template <typename Str>
static Str try_strip_diacritics(
Str const& input,
std::locale const& loc = std::locale())
{
using Ch = typename Str::value_type;
using T = boost::locale::utf::utf_traits<Ch>;
auto tmp = boost::locale::normalize(
input, boost::locale::norm_nfd, loc);
auto f = tmp.begin(), l = tmp.end(), out = f;
while (f!=l) {
switch(*f) {
case 'xcc':
case 'xcd': // TODO find more
T::decode(f, l);
break; // skip
default:
out = T::encode(T::decode(f, l), out);
break;
}
}
tmp.erase(out, l);
return tmp;
}

打印(在我的盒子上!

Before: "élève"  0xc3 0xa9 0x6c 0xc3 0xa8 0x76 0x65
all-in-one: "eleve"  0x65 0x6c 0x65 0x76 0x65

较旧的答案文本/分析:

#include <boost/locale.hpp>
#include <iomanip>
#include <iostream>
static void dump(std::string const& s) {
std::cout << std::hex << std::showbase << std::setfill('0');
for (uint8_t ch : s)
std::cout << " " << std::setw(4) << int(ch);
std::cout << std::endl;
}
int main() {
boost::locale::generator gen;
std::string const pupil(u8"élève");
std::string const str =
boost::locale::normalize(
pupil,
boost::locale::norm_nfd,
gen(""));
std::cout << "Before: "; dump(pupil);
std::cout << "After:  "; dump(str);
}

打印,在我的盒子上:

Before:  0xc3 0xa9 0x6c 0xc3 0xa8 0x76 0x65
After:   0x65 0xcc 0x81 0x6c 0x65 0xcc 0x80 0x76 0x65

然而,在科里鲁上,这没有什么区别。这表示它取决于可用/系统区域设置。

文档说:https://www.boost.org/doc/libs/1_72_0/libs/locale/doc/html/conversions.html#conversions_normalization

Unicode 规范化是将字符串转换为 标准形式,适用于文本处理和比较。为 例如,字符"ü"可以由单个码位或 字符"U"和"Diaeresis"̈"的组合。正常化 是 Unicode 文本处理的重要组成部分。

Unicode 定义了四种规范化形式。每个特定形式都是 由传递给规范化函数的标志选择:

  • NFD - 规范分解 -boost::locale::norm_nfd
  • NFC - 规范分解,然后是规范组合 - boost::locale::norm_nfc 或boost::locale::norm_default
  • NFKD - 兼容性分解 -boost::locale::norm_nfkd
  • NFKC - 兼容性分解,然后是规范组合 -boost::locale::norm_nfkc

有关规范化形式的更多详细信息,请阅读 [本文][1]。

你可以做什么

似乎您可以通过仅执行分解(因此 NFD(然后删除任何非 alpha 的代码点来获得某种方法。

这是作弊,因为它假设所有代码点都是单单元的,这通常不是正确的,但对于示例,它确实有效:

请参阅上面的改进版本,该版本确实迭代了代码点而不是字节。