facet ändern



  • Hallo,
    habe ein facet zum anpassen von is_blank erstellt.

    struct fixed_blank_ctype : std::ctype<char>
    {
       fixed_blank_ctype(void) : std::ctype<char>(table())
       {
       }
    
       static auto table(void) noexcept -> const std::ctype_base::mask*
       {
          static mdt::category_table<std::ctype_base::mask, 256> s_table;
          fix_blank_category(s_table);
          return s_table.data();
       }
    };
    

    wenn ich nun z.b. ein deutsches locale erstellen will, dann wird es mit einem std::locale("*") erstellt.

       mdt::fixed_blank_ctype *ger_ctype = new mdt::fixed_blank_ctype();
       std::locale ger_loc = std::locale(std::locale("de"), ger_ctype);
       std::locale::global(ger_loc);
       std::cout << "üöäÜÖÄ" << std::endl;
       std::cout << "locale: " << ger_loc.name() << std::endl;
    

    ausgabe:

    ³÷õ▄Í─
    locale: *
    

    wenn ich aber ger_ctype einen nullptr zuweise:

       mdt::fixed_blank_ctype *ger_ctype = nullptr; //new mdt::fixed_blank_ctype();
       std::locale ger_loc = std::locale(std::locale("de"), ger_ctype);
       std::locale::global(ger_loc);
       std::cout << "üöäÜÖÄ" << std::endl;
       std::cout << "locale: " << ger_loc.name() << std::endl;
    

    ausgabe:

    üöäÜÖÄ
    locale: de
    

    woher kommt das?

    Meep Meep



  • s. z.B. std::locale::locale:

    1. Constructs a copy of other except for the facet of type Facet (typically deduced from the type of the argument) which is installed from the argument facet. If facet is NULL, the constructed locale is a full copy of other. The locale constructed in this manner has no name.

    Ich denke, der letzte Satz bezieht sich dann nur auf den ersten.
    Also bei NULL eine komplette Kopie oder ein neues locale ohne Namen (d.h. "*").



  • hallo,

    aber wie mache ich das dann, damit ich umlaute ausgeben kann? ich war der meinung das, bis auf die table, sonst alles beim alten bleibt. also ein locale("de") objekt sein muesste.



  • hab mal folgenden code online (https://rextester.com/l/cpp_online_compiler_gcc) compiliert:

    template<class CHAR_TYPE>
    class umlaut : public std::ctype_byname<CHAR_TYPE>
    {
       protected:
          virtual auto do_is_umlaut(CHAR_TYPE c) const -> bool
          {
             switch(c)
             {
                case 'ä':
                case 'ö':
                case 'ü':
                case 'Ä':
                case 'Ö':
                case 'Ü': return true;
                default: return false;
             }
          }
    
       public:
          explicit umlaut(size_t refs = 0) : std::ctype_byname<CHAR_TYPE>("de", refs)
          {
          }
    
          auto is_umlaut(CHAR_TYPE c) const -> bool
          {
             return do_is_umlaut(c);
          }
    }; /* class umlaut */
    
    int main()
    {
        std::locale ger_loc(std::locale("de_DE.UTF-8"), new umlaut<char>);
        std::locale::global(ger_loc);
        std::cout.imbue(ger_loc);
        std::cout << "üöäÜÖÄ" << std::endl;
        std::cout << "locale: " << ger_loc.name() << std::endl;
    
        return 0;
    }
    

    ausgabe:

    üöäÜÖÄ
    locale: *
    

    unter windows mit VS2019 und locale name "de" kommt

    ³÷õ▄Í─
    locale: *
    

    ein bug in VS2019?



  • Nein ein Problem der windows "console" die kann kein UTF-8 bei default.
    AFAIK muss man die verwendete codepage der console ändern.



  • ich hab doch geschrieben das ich das locale unter VS2019 mit dem string "de" erzeuge und nicht mit UTF8. solange ich nicht mein eigenes facet mit reinschiebe funktioniert die ausgabe mit den umlauten. aber wenn ich bei der erzeugung mein facet mit angebe, scheint er auf das classic locale zurück zu gehen.



  • unter VS2017 ist es das selbe. Ist uebrigens ein beispiel aus dem buch "Standard C++ IOStreams and Locales" von Angelika Langer.

    hat jemand unter windows einen nicht- microsoft compiler am laufen und koennte den letzten code mal testen? aufpassen auf den locale namen, unter visual studio heisst er z.b. "de".



  • Wie sind die umlaute im quellcode kodiert? (Die Byte Darstellung)
    Wenn du den quellcode in utf8 hast, dann funktioniert die "de" locale nicht da AFAIK die "de" lokale kein Unicode ist.
    Der Code aber ein utf8 kodiertes zeichen ausgeben möchte.

    AFAIK sollte ein facet das entsprechen konvertieren können/sollen. Was wohl aber unter windows nicht funktioniert



  • Falls der quellcode nicht in utf-8 kodiert ist, versuch mal die umlaute im quellcode direkt als utf-8 anzugeben.
    Und zwar als oktale:

    // ä: \303\244 (C3 A4)
    // ö: \303\266 (C3 B6)
    // ü: \303\274 (C3 BC)
    // Ä: \303\204 (C3 84)
    // Ö: \303\226 (C3 96)
    // Ü: \303\234 (C3 9C)



  • @Meep-Meep sagte in facet ändern:

    ich hab doch geschrieben das ich das locale unter VS2019 mit dem string "de" erzeuge und nicht mit UTF8. solange ich nicht mein eigenes facet mit reinschiebe funktioniert die ausgabe mit den umlauten. aber wenn ich bei der erzeugung mein facet mit angebe, scheint er auf das classic locale zurück zu gehen.

    naja hier erstellst du schon eine utf-8 lokale bzw erfragst diese:

    std::locale ger_loc(std::locale("de_DE.UTF-8"), new umlaut<char>);
    

    Und laut dieser dokumenation von microsoft funktioniert utf-8 nicht unter windows.
    Es bezieht sich hier auf setlocale aber das grundlegende Problem bleibt erhalten dass windows kein utf-8 in der ANSI api (char) kann.

    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=vs-2019:

    The locale argument can take a locale name, a language string, a language string and country/region code, a code page, or a language string, country/region code, and code page.
    The set of available locale names, languages, country/region codes, and code pages includes all those supported by the Windows NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8. If you provide a code page value of UTF-7 or UTF-8, setlocale will fail, returning NULL. The set of locale names supported by setlocale are described in Locale Names, Languages, and Country/Region Strings. The set of language and country/region strings supported by setlocale are listed in Language Strings and Country/Region Strings. We recommend the locale name form for performance and for maintainability of locale strings embedded in code or serialized to storage. The locale name strings are less likely to be changed by an operating system update than the language and country/region name form.

    Anders beispiel: https://github.com/ocornut/imgui/issues/917



  • @Firefly: Du verwirrst hier zuviel. @Meep-Meep hat doch im ersten Beitrag geschrieben, daß die Umlaute korrekt mit "de" ausgegeben werden.

    @Meep-Meep:
    Zum Test probiere mal

    std::locale loc_ger("de");
    const auto &f = std::use_facet<std::ctype<char>>(loc_ger);
    std::locale loc = std::locale(loc_ger, &f);
    std::locale::global(loc);
    std::cout << "üöäÜÖÄ" << std::endl;
    std::cout << "locale: " << loc.name() << std::endl;
    

    Dann sollten auch die Umlaute korrekt ausgegeben werden, ansonsten wäre dieser Konstruktor falsch implementiert.
    Du kannst es sonst auch mal mit anderen Facets (bei use_facet<...>) ausprobieren.



  • hi TH69,

    ausgabe:

    ³÷õ▄Í─
    locale: *
    

    das selbe in gruen.

    nun mit einem anderen facet:

       std::locale loc_ger("de");
       std::locale loc_en("en");
       const auto &f = std::use_facet<std::money_get<char>>(loc_en);
       std::locale loc = std::locale(loc_ger, &f);
       std::locale::global(loc);
       std::cout << "üöäÜÖÄ" << std::endl;
       std::cout << "locale: " << loc.name() << std::endl;
    

    ausgabe:

    ³÷õ▄Í─
    locale: *
    

    nun mit einem nullptr als facet:

       std::locale loc_ger("de");
       std::locale loc_en("en");
       const auto *f = &std::use_facet<std::money_get<char>>(loc_en);
       f = nullptr;
       std::locale loc = std::locale(loc_ger, f);
       std::locale::global(loc);
       std::cout << "üöäÜÖÄ" << std::endl;
       std::cout << "locale: " << loc.name() << std::endl;
    

    ausgabe:

    üöäÜÖÄ
    locale: de
    


  • Dann würde ich ja sagen, daß die Implementierung kaputt ist, denn mindestens die erste Ausgabe sollte ja wie die dritte sein (denn es wird ja das eigene Facet angegeben).

    Evtl. liegt es intern daran, daß dieser locale keinen Namen mehr hat (*) und dann auf classic ("C") umgestellt wird.

    Kommt denn bei "C" und "" die selbe Ausgabe?



  • gestern hatte ich ja auf rextester.com einen test gemacht und da kam:

    üöäÜÖÄ
    locale: *
    

    also das lokal wird umbenannt. das scheint in ordnung zu sein.

    zu locales "C" und "". ich hab deine frage mal folgend interpretiert:

       std::locale loc_ger("");
       std::locale loc_en("C");
       const auto &f = std::use_facet<std::money_get<char>>(loc_en);
       std::locale loc = std::locale(loc_ger, &f);
       std::locale::global(loc);
       std::cout.imbue(loc);
       std::cout << "üöäÜÖÄ" << std::endl;
       std::cout << "locale: " << loc.name() << std::endl;
    

    kommt wieder:

    ³÷õ▄Í─
    locale: *
    


  • Wenn dort also dieselben Zeichen ausgegeben werden, dann bestätigt das meine Vermutung.
    Ein Workaround fällt mir leider auch nicht ein, denn der Facet-Konstruktor ist wohl die einzige Möglichkeit bei einem bestehenden locale-Objekt ein Facet zu ändern.



  • hab mal nen bug report geschrieben. mal schauen ob das was bringt...
    hab vor 2.5 jahren schon mal einen wegen std::ctype<char>::::is(std::blank, ch) geschrieben, weil std::ctype_base::blank gleich wie std::ctype_base::space agiert, ist bis jetzt auch noch nix passiert. steht seit meinem bug report Mai 2017 auf "Under Investigation" 😕



  • Bei dem von dir geposteten Online-Compiler rextester kommen aber bei "VC++ [19.00.23506 for x64]" mit dem Testcode die richtigen Umlaute heraus.



  • @Th69 sagte in facet ändern:

    Bei dem von dir geposteten Online-Compiler rextester kommen aber bei "VC++ [19.00.23506 for x64]" mit dem Testcode die richtigen Umlaute heraus.

    Dann klingt das ganze eventuell nach einem reinem darstellungsproblem.

    Die Frage ist wie kommen wir an die byte (hexadezimal) Darstellung der Ausgabe. Nicht das doch UTF-8 ausgegeben werden soll aber die "Konsole" die zeichen als ANSI oder in einer anderen codepage interpretiert.
    Oder das die Ausgabe kein unicode ist aber die zeichen als unicode interpretiert werden



  • Man könnte die Ausgabe in der Konsole ja per >file.txt in eine Datei umleiten (und dann mit einem Hex-Editor anschauen).



  • @Meep-Meep:

    Gibt es einen unterschied der Darstellung bei folgenden code?

    #include <iostream>
    #include <locale>
    
    int main()
    {
        std::locale loc_ger("de");
    const auto &f = std::use_facet<std::ctype<char>>(loc_ger);
    std::locale loc = std::locale(loc_ger, &f);
    std::locale::global(loc);
    std::cout << "üöäÜÖÄ" << std::endl;
    std::cout << "locale: " << loc.name() << std::endl;
    std::cout << "utf-8 encoded: \303\274\303\266\303\244\303\234\303\226\303\204" << std::endl;
    }
    

    Die utf-8 encoded enthält üöäÜÖÄ utf-8 kodiert in oktaler schreibweise.

    Bei https://rextester.com/l/cpp_online_compiler_visual bekomme ich folgende ausgabe:

    üöäÜÖÄ
    locale: *
    utf-8 encoded: üöäÜÖÄ

    Also identisch


Log in to reply