17

問題:一方のマシンで動作し、もう一方のマシンでは失敗する、対応するテストケースを持つメソッドがあります(詳細は以下を参照)。コードに何か問題があり、1台のマシンで偶然に動作する原因になっていると思います。残念ながら、問題を見つけることができません。

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"));
}

失敗したテスト(2台のマシンのうちの1台でのみ発生):

Failure
Value of: firstCharToUpperUtf8("ßfoo")
  Actual: "\xE1\xBA\x9E" "foo"
Expected: "ßfoo"

両方のマシンにロケールen_US.utf8がインストールされています。ただし、異なるバージョンのlibcを使用します。コンパイルされた場所に関係なくGLIBC_2.14を搭載したマシンで動作し、他のマシンでは動作しませんが、適切なlibcバージョンがないため、そこでのみコンパイルできます。

いずれにせよ、このコードをコンパイルして、失敗したときに実行するマシンがあります。コードに何か問題があるはずですが、どうなるのでしょうか。C ++メソッド(特にSTL)を指すことも素晴らしいでしょう。ブーストや他のライブラリは、他の外部要件のために避ける必要があります。

4

5 に答える 5

10

多分誰かがそれを使うでしょう(多分テストのために)

これを使用すると、単純なコンバーターを作成できます:)追加のライブラリはありません:)

http://pastebin.com/fuw4Uizk

1482文字

Ь <> ь
Э <> э
Ю <> ю
Я <> я
Ѡ <> ѡ
Ѣ <> ѣ
Ѥ <> ѥ
Ѧ <> ѧ
Ѩ <> ѩ
Ѫ <> ѫ
Ѭ <> ѭ
Ѯ <> ѯ
Ѱ <> ѱ
Ѳ <> ѳ
Ѵ <> ѵ
Ѷ <> ѷ
Ѹ <> ѹ
Ѻ <> ѻ
Ѽ <> ѽ
Ѿ <> ѿ
Ҁ <> ҁ
Ҋ <> ҋ
Ҍ <> ҍ
Ҏ <> ҏ
Ґ <> ґ
Ғ <> ғ
Ҕ <> ҕ
Җ <> җ
Ҙ <> ҙ
Қ <> қ
Ҝ <> ҝ
Ҟ <> ҟ
Ҡ <> ҡ
Ң <> ң
于 2013-09-08T23:15:09.073 に答える
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);
}
于 2015-10-10T21:23:14.947 に答える
1

そのテストケースでは、ドイツ語のß文字の大文字バージョンはどうなると思いますか?

言い換えれば、あなたの基本的な仮定は間違っています。

コメントのウィキペディアには次のように記載されていることに注意してください。

Sharp sは、従来の大文字の形式がないという点でラテンアルファベットの文字の中でほぼユニークです(他の数少ない例の1つは、グリーンランド語で使用されたkra、ĸです)。これは、最初はドイツ語のテキストでは発生せず、従来のドイツ語の印刷(ブラックレターを使用)ではすべて大文字を使用しなかったためです。オールキャップスを使用する場合、現在のスペル規則では、ßをSSに置き換える必要があります。[1] ただし、2010年には、地名をすべて大文字で書く場合、公式文書でその使用が義務付けられました。[2]

したがって、最初に鋭いsが発生する基本的なテストケースは、ドイツ語の規則に違反しています。元のポスターの前提が間違っているという点で、私はまだポイントがあると思います。すべての言語で、文字列は一般に大文字と小文字の間で自由に変換できません。

于 2012-09-19T11:09:28.163 に答える
1

小さなケースの鋭いs:ß; 大文字のシャープs:ẞ。アサーションで大文字バージョンを使用しましたか?glibg 2.14は、unicode5.1より前のシャープの大文字バージョンを実装していないようです。他のマシンでは、libcはunicode5.1を使用しますẞ= U1E9E .. ..

于 2012-09-19T12:10:20.493 に答える
0

問題は、アサートしないロケールが準拠していること、アサートが発生するロケールが準拠していないことです。

B.1.2で必要なテクニカルレポートN897LC_CTYPE [理論的根拠]:

LC_CTYPE文字クラスはC標準の文字クラス定義に基づいているため、このカテゴリは複数文字要素をサポートしていません。たとえば、ドイツ語の文字は伝統的に小文字として分類されます。対応する大文字はありません。ドイツ語のテキストを適切に大文字化すると、SSに置き換えられます。つまり、2文字です。この種の変換は、toupperおよびtolowerキーワードの範囲外です。

このテクニカルレポートは、2001年12月25日に公開されました。しかし、によると:https ://en.wikipedia.org/wiki/Capital_%E1%BA%9E

2010年、ドイツの公式文書では、地名をすべて大文字で書くときに大文字ẞの使用が義務付けられました。

しかし、このトピックは標準委員会によって再検討されていないため、ドイツ政府の発言とは技術的に独立しているため、の標準化された動作はtoupperß文字に変更を加えないことです。

これがマシン上で一貫して機能しない理由は次のsetlocaleとおりです。

指定されたシステムロケールまたはその部分を新しいCロケールとしてインストールします

したがって、これは非準拠のシステムロケールであり、ß文字を変更するようにen_US.utf8指示しています。toupper残念ながら、スペシャライゼーションctype<char>::clasic_tableはで利用ctype<wchar_t>できないため、動作を変更することはできません。2つのオプションを残します:

  1. 可能なすべての小文字から対応する大文字へのconst map<wchar_t, wchar_t>変換用にを作成しますwchar_twchar_t
  2. L'ß'次のようなチェックを追加します。

    int ret = wcrtomb(buf, wChar == L'ß' ? L'ẞ' : towupper(wChar), &state);
    

Live Example

于 2016-06-01T14:20:25.490 に答える