问题: 有一个方法和对应的测试用例,在一台机器上可以运行,但在另一台机器上失败了(详见下文)。我认为代码有问题,在一台机器上偶然成功。不幸的是,我找不到问题所在。
请注意,我无法真正影响使用std::string和utf-8编码的需求。使用C ++方法完全没问题,但不幸的是我找不到任何东西。因此使用C函数。
该方法:
std::string firstCharToUpperUtf8(const string& orig) {
std::string retVal;
retVal.reserve(orig.size());
std::mbstate_t state = std::mbstate_t();
char buf[MB_CUR_MAX + 1];
size_t i = 0;
if (orig.size() > 0) {
if (orig[i] > 0) {
retVal += toupper(orig[i]);
++i;
} else {
wchar_t wChar;
int len = mbrtowc(&wChar, &orig[i], MB_CUR_MAX, &state);
// If this assertion fails, there is an invalid multi-byte character.
// However, this usually means that the locale is not utf8.
// Note that the default locale is always C. Main classes need to set them
// To utf8, even if the system's default is utf8 already.
assert(len > 0 && len <= static_cast<int>(MB_CUR_MAX));
i += len;
int ret = wcrtomb(buf, towupper(wChar), &state);
assert(ret > 0 && ret <= static_cast<int>(MB_CUR_MAX));
buf[ret] = 0;
retVal += buf;
}
}
for (; i < orig.size(); ++i) {
retVal += orig[i];
}
return retVal;
}
测试:
TEST(StringUtilsTest, firstCharToUpperUtf8) {
setlocale(LC_CTYPE, "en_US.utf8");
ASSERT_EQ("Foo", firstCharToUpperUtf8("foo"));
ASSERT_EQ("Foo", firstCharToUpperUtf8("Foo"));
ASSERT_EQ("#foo", firstCharToUpperUtf8("#foo"));
ASSERT_EQ("ßfoo", firstCharToUpperUtf8("ßfoo"));
ASSERT_EQ("Éfoo", firstCharToUpperUtf8("éfoo"));
ASSERT_EQ("Éfoo", firstCharToUpperUtf8("Éfoo"));
}
测试失败(仅发生在两台计算机中的一台上):
Failure
Value of: firstCharToUpperUtf8("ßfoo")
Actual: "\xE1\xBA\x9E" "foo"
Expected: "ßfoo"
这两台机器都安装了en_US.utf8语言环境。但它们使用的libc版本不同。无论在哪台机器上编译,代码都可以在使用GLIBC_2.14的机器上正常运行,但在另一台机器上无法正常运行,只能在该机器上编译,否则就会缺少适当的libc版本。
无论如何,在一个机器上编译并运行此代码是正确的,而在另一个机器上则失败了。代码肯定有问题,我想知道是什么问题。指出C++方法(特别是STL)也很好。由于其他外部要求,应避免使用Boost和其他库。
orig[i] > 0
替换为(orig[i] & (1 << 7)) == 0
,因为原始测试在char
为无符号的系统(例如 ARM 上的 Linux)上不起作用。 - Niklas Schnelle