我正在尝试为 ICU 的 BreakIterator 类设置一个包装器来进行边界分析,但在初始化过程中遇到了一个奇怪的问题。
设置 Break Iterator 后,错误代码状态始终设置为 U_USING_DEFAULT_WARNING。
根据文档:
U_USING_DEFAULT_WARNING 表示使用了默认的语言环境数据;找不到所请求的语言环境及其任何后备语言环境。
但是我尝试过的语言环境(en_US、ja_JP)绝对有效并且存在于我的系统上。它们甚至会通过 getAvailableLocales 显示在 ICU 列表中。但错误仍然存在。
这是我的代码,或多或少:
#include <iostream>
#include <memory>
#include <stdexcept>
#include <algorithm>
#include <unicode/brkiter.h>
#include <unicode/locid.h>
class WordIterator
{
icu::UnicodeString _u16Data;
std::unique_ptr<icu::BreakIterator> _itr = nullptr;
bool _word;
int32_t _begin, _cur, _next;
UErrorCode _err;
public:
WordIterator(const std::string& data, const icu::Locale& locale)
{
_u16Data = icu::UnicodeString::fromUTF8(data);
_err = U_ZERO_ERROR;
_itr.reset(icu::BreakIterator::createWordInstance(locale, _err));
if (U_FAILURE(_err)) {
throw std::runtime_error("Failed to create iterator");
}
_itr->setText(_u16Data);
_begin = _itr->first();
_cur = _begin;
_next = _itr->next();
}
auto getError() const {
return _err;
}
};
int main()
{
int count = 0;
auto locales = icu::Locale::getAvailableLocales(count);
auto lc = std::find_if(locales, locales+count, [](icu::Locale search) {
auto name = search.getName();
auto code = std::string{name};
return code == "en_US";
});
if (lc != locales+count) {
std::cerr << "Locale was found.\n";
}
WordIterator br{"This is a test.", icu::Locale::createCanonical("en_US")};
if (br.getError() == U_USING_DEFAULT_WARNING) {
std::cerr << "Default warning.\n";
}
return 0;
}
知道我做错了什么吗?我需要在某处做一些额外的初始化吗? U_FAILURE 认为至少是成功的。
我应该提到,我正在 Ubuntu 22.04 和 ICU 70.1 上进行测试,如果这有什么区别的话。
调用
icu::BreakIterator::createWordInstance
时,库会在其内部资源包中搜索所需的 "boundaries"
规则集(类型为 "word"
的规则集)。此步骤还在给定区域设置上执行fallback以查找这样的规则集。
您可以在返回的中断迭代器实例上调用方法
getLocale(ULOC_ACTUAL_LOCALE, get_status)
,以评估正在使用的实际语言环境。 99% 的情况下,您会发现该区域设置的名称为空(正在应用根规则)。
您不应将 U_USING_DEFAULT_WARNING
的结果代码
BreakIterator::createXxxInstance
视为 警告,因为 只有少数语言环境具有 存储的规则集。
大多数语言环境都会退回到根规则,这些规则分别来自 char.txt、word.txt、line.txt 和 sent.txt,分别表示字素簇、单词、行和句子中断。
对于单词迭代器,我可以找到仅为“瑞典语(芬兰)”定义的规则集(
sv_FI
)。如果您用您的代码尝试它,您将不会收到警告。