c++setw

setw and accentuated characters


I want to display a "pretty" list of countries and their ISO currency codes on C++. The issue is that my data is in French and it has accentuated characters. That means that Algeria, actually is written "Algérie" and Sweden becomes "Suède".

map<string, string> currencies; /* ISO code for currency and country name: CAD/Canada */ 
for (auto &cursor: countries)
  cout << setw(15) << left << cursor.second << right << " - " cursor.first << endl;

If the map contains Algeria, Canada and Sweden the result comes out something like this:

Canada          - CAD
Algérie        - DZD
Suède          - SEK

Do you see how Algeria and Sweden are not "pretty"? That's because even though "Algérie" has 7 visible characters and "Suède" has 5, they "count" as one more for setw. The "é" in "Algérie" and the "è" in "Suède" "count" as two characters, because they are "special accentuated characters.

Is there an elegant and simple way to make sure that DZD and SEK get automatically aligned with CAD?


Solution

    1. Convert to using std::wstring instead of std::string
    2. Convert to using wide string constants (L"stuff" vs "stuff")
    3. Convert to using std::wcout instead of std::cout
    4. Use setlocale to set a UTF-8 locale
    5. Use wcout.imbue to configure wcout for a UTF-8 locale

    Example:

    #include <map>
    #include <string>
    #include <iostream>
    #include <iomanip>
    #include <locale>
    
    int main() {
        setlocale(LC_ALL, "en_US.utf8");
        std::locale loc("en_US.UTF-8");
        std::wcout.imbue(loc); 
        std::map<std::wstring, std::wstring> dict 
            { {L"Canada",L"CAD"}, {L"Algérie",L"DZD"}, {L"Suède",L"SEK"} };
        for (const auto& [key, value]: dict) {
            std::wcout << std::setw(10) << key << L" = " << value << std::endl;
        }
    }