C/C++ UTF-8大/小写转换

b.b*_*old 16 c c++ utf-8 case-conversion

问题:有一种方法可以在一台机器上运行相应的测试用例而在另一台机器上运行失败(详情如下).我认为代码有问题,导致它在一台机器上偶然工作.不幸的是我找不到问题.

请注意,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;
}
Run Code Online (Sandbox Code Playgroud)

考试:

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"));
}
Run Code Online (Sandbox Code Playgroud)

失败的测试(仅在两台机器中的一台上发生):

Failure
Value of: firstCharToUpperUtf8("ßfoo")
  Actual: "\xE1\xBA\x9E" "foo"
Expected: "ßfoo"
Run Code Online (Sandbox Code Playgroud)

两台机器都安装了locale en_US.utf8.然而,他们使用不同版本的libc.它在GLIBC_2.14的机器上工作,与编译的位置无关,在其他机器上不起作用,而只能在那里编译,因为否则它缺少正确的libc版本.

无论哪种方式,都有一台机器可以编译此代码并在失败时运行它.代码有问题,我想知道是什么.指向C++方法(特别是STL),也会很棒.由于其他外部要求,应避免使用Boost和其他库.

Daw*_*ozd 9

也许有人会使用它(可能用于测试)

有了这个,你可以做简单的转换器:)没有额外的库:)

http://pastebin.com/fuw4Uizk

1482封信件

? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
? <> ?
Run Code Online (Sandbox Code Playgroud)


Ger*_*esp 5

下面的 C++11 代码对我有用(暂时忽略了应该如何翻译尖锐的 s 的问题——它保持不变。无论如何它正在慢慢地从德语中淘汰)。

优化和大写首字母仅作为练习。

编辑:正如所指出的,codecvt 似乎已被弃用。然而,它应该保留在标准中,直到定义了合适的替代品。请参阅已弃用的标头 <codecvt> 替换

#include <codecvt>
#include <iostream>
#include <locale>

std::locale const utf8("en_US.UTF-8");

// Convert UTF-8 byte string to wstring
std::wstring to_wstring(std::string const& s) {
  std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
  return conv.from_bytes(s);
}

// Convert wstring to UTF-8 byte string
std::string to_string(std::wstring const& s) {
  std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
  return conv.to_bytes(s);
}

// Converts a UTF-8 encoded string to upper case
std::string tou(std::string const& s) {
  auto ss = to_wstring(s);
  for (auto& c : ss) {
    c = std::toupper(c, utf8);
  }
  return to_string(ss);
}

void test_utf8(std::ostream& os) {
  os << tou("foo" ) << std::endl;
  os << tou("#foo") << std::endl;
  os << tou("ßfoo") << std::endl;
  os << tou("Éfoo") << std::endl;
}    

int main() {
  test_utf8(std::cout);
}
Run Code Online (Sandbox Code Playgroud)


小智 1

小写升号 s : \xc3\x9f; 大写升号 s :\xe1\xba\x9e。您在断言中使用了大写版本吗?\n似乎 glibg 2.14 遵循 unicode5.1 之前的版本,没有 Sharp s 的大写版本,而在另一台机器上,libc 使用 unicode 5.1 \xe1\xba\x9e=U1E9E ...

\n

  • 这是错误的。许多代码点在案例之间具有一对一的映射。您必须对字符串而不是字符进行大小写映射,否则您的结果很糟糕。U+00DF 的正确大写是“SS”。它*不是* U+1E9E!!参见都柏林大学。 (7认同)
  • @tchrist:用“SS”大写 U+00DF 对于“in Maßen”(小而适度的[数量])来说是不正确的,因为它将导致“IN MASSEN”(大量的大[数量])。Maßen 和 Massen 在德语中是不同的词,实际上是相反的词,类似于 Maße(度量)和 Masse(质量)。 (4认同)