c++ c utf-8 case-conversion

C/C++ UTF-8 conversiones mayúsculas/minúsculas



case-conversion (5)

¿Cuál espera que sea la versión en mayúsculas del carácter ß alemán para ese caso de prueba?

En otras palabras, sus suposiciones básicas son erróneas.

Tenga en cuenta que la Wikipedia en el comentario dice:

Sharp s es casi único entre las letras del alfabeto latino, ya que no tiene una forma mayúscula tradicional (uno de los otros pocos ejemplos es kra,, que se usó en groenlandés). Esto se debe a que nunca aparece inicialmente en el texto en alemán, y la impresión en alemán tradicional (que utiliza blackletter) nunca usó mayúsculas. Cuando se usan mayúsculas, las reglas actuales de ortografía requieren el reemplazo de ß con SS. [1] Sin embargo, en 2010 su uso se convirtió en obligatorio en la documentación oficial al escribir nombres geográficos en mayúsculas. [2]

Por lo tanto, el caso de prueba básico, con los marcados como una inicial, está violando las reglas del alemán. Todavía creo que tengo un punto, ya que la premisa original de los carteles es incorrecta, las cadenas no se pueden convertir libremente en mayúsculas y minúsculas, para todos los idiomas.

El problema: existe un método con un caso de prueba correspondiente que funciona en una máquina y falla en la otra (detalles a continuación). Supongo que hay algo mal con el código, lo que hace que funcione por casualidad en una máquina. Desafortunadamente no puedo encontrar el problema.

Tenga en cuenta que el uso de std :: string y la codificación utf-8 son requisitos en los que no tengo ninguna influencia real. Usar métodos de C ++ sería totalmente correcto, pero desafortunadamente no pude encontrar nada. De ahí el uso de las funciones C.

El método:

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

La prueba:

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

La prueba fallida (solo sucede en una de dos máquinas):

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

Ambas máquinas tienen la configuración regional en_US.utf8 instalada. Sin embargo, utilizan diferentes versiones de libc. Funciona en la máquina con GLIBC_2.14 independientemente de donde se compiló y no funciona en la otra máquina, mientras que solo se puede compilar allí, porque de lo contrario carece de la versión libc adecuada.

De cualquier manera, hay una máquina que compila este código y lo ejecuta mientras falla. Tiene que haber algo mal con el código y me pregunto qué. Apuntar a los métodos de C ++ (STL en particular), también sería genial. Deben evitarse el refuerzo y otras bibliotecas debido a otros requisitos externos.


El problema es que las configuraciones regionales que no se cumplen son compatibles, las configuraciones regionales en las que se ejecuta la afirmación no son compatibles.

Informe técnico N897 requerido en B.1.2 [Justificación de LC_CTYPE ]:

Como las clases de caracteres LC_CTYPE se basan en la definición de clase de caracteres estándar de C, la categoría no admite elementos de caracteres múltiples. Por ejemplo, el carácter alemán se clasifica tradicionalmente como una letra minúscula. No hay letra mayúscula correspondiente; en la capitalización adecuada del texto alemán, será reemplazado por SS; Es decir, por dos personajes. Este tipo de conversión está fuera del alcance de las palabras clave de toupper y tolower .

Este Informe Técnico fue publicado en diciembre-25-''01. Pero de acuerdo con: https://en.wikipedia.org/wiki/Capital_%E1%BA%9E

En 2010, el uso de la capital ẞ se convirtió en obligatorio en la documentación oficial en Alemania al escribir nombres geográficos en mayúsculas

Pero el comité estándar no ha vuelto a examinar el tema, por lo que, técnicamente, independientemente de lo que diga el gobierno alemán, el comportamiento estandarizado de toupper debe hacer cambios en el carácter ß.

La razón por la que esto funciona de manera inconsistente en las máquinas es setlocale :

Instala la configuración regional del sistema especificada o su parte como la nueva configuración regional de C

Por lo tanto, la configuración regional del sistema no compatible, en_US.utf8 , le en_US.utf8 que modifique el carácter ß. Desafortunadamente, la especialización ctype<char>::clasic_table , no está disponible en ctype<wchar_t> por lo que no puede modificar el comportamiento. Dejándote con 2 opciones:

  1. Cree un const map<wchar_t, wchar_t> para la conversión de cada posible wchar_t minúsculas al correspondiente wchar_t mayúsculas
  2. Agregue un cheque para un L''ß'' como este:

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

Ejemplo vivo


El siguiente código de C ++ 11 funciona para mí (sin tener en cuenta por un momento la cuestión de cómo deberían traducirse los sharp s --- no se modifica. De todos modos, lentamente se está eliminando del alemán).

Las optimizaciones y las mayúsculas solo en la primera letra se dejan como ejercicio.

Edición: Como se señaló, el codecvt parece haber quedado en desuso. Sin embargo, debe permanecer en el estándar hasta que se defina un reemplazo adecuado. Ver cabecera obsoleta <codecvt> reemplazo

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


Tal vez alguien lo usaría (tal vez para pruebas)

Con esto podrías hacer un simple conversor :) No hay librerías adicionales :)

http://pastebin.com/fuw4Uizk

1482 letras

Ejemplo

Ь <> ь Э <> э Ю <> ю Я <> я Ѡ <> ѡ Ѣ <> ѣ Ѥ <> ѥ Ѧ <> ѧ Ѩ <> ѩ Ѫ <> ѫ Ѭ <> ѭ Ѯ <> ѯ Ѱ <> ѱ Ѳ <> ѳ Ѵ <> ѵ Ѷ <> ѷ Ѹ <> ѹ Ѻ <> ѻ Ѽ <> ѽ Ѿ <> ѿ Ҁ <> ҁ Ҋ <> ҋ Ҍ <> ҍ Ҏ <> ҏ Ґ <> ґ Ғ <> ғ Ҕ <> ҕ Җ <> җ Ҙ <> ҙ Қ <> қ Ҝ <> ҝ Ҟ <> ҟ Ҡ <> ҡ Ң <> ң


caja pequeña sharp s: ß; mayúscula aguda s: ẞ. ¿Usaste la versión en mayúsculas en tu declaración? Parece que glibg 2.14 sigue implementos pre unicode5.1 sin versión mayúscula de sharp s, y en la otra máquina el libc usa unicode 5.1 ẞ = U1E9E ...