2012-02-26 8 views
5

У меня есть простая программа, которая проверяет преобразование между wchar_t и char, используя серию локалей, переданных ему в командной строке. Он выводит список преобразований, которые не удается распечатать имя локали и строку, которая не удалось преобразовать.xlocale сломан на OS X?

Я строю его с помощью clang и libC++. Мое понимание заключается в том, что поддержка языка libC++ по умолчанию поддерживается библиотекой xlocale на OS X.

Я вижу некоторые неожиданные сбои, а также некоторые случаи, когда преобразование должно завершиться неудачей, но это не так.

Вот программа.

#warning call this program like: "locale -a | ./a.out" or pass \ 
locale names valid for your platform, one per line via standard input 

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

template <class Facet> 
class usable_facet : public Facet { 
public: 
    // FIXME: use inheriting constructors when available 
    // using Facet::Facet; 
    template <class ...Args> 
    usable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {} 
    ~usable_facet() {} 
}; 

int main() { 
    std::array<std::wstring,11> args = {L"a",L"é",L"¤",L"€",L"Да",L"Ψ",L"א",L"আ",L"✈",L"가",L""}; 

    std::wstring_convert<usable_facet<std::codecvt_utf8<wchar_t>>> u8cvt; // wchar_t uses UCS-4/UTF-32 on this platform 

    int convert_failures = 0; 
    std::string line; 
    while(std::getline(std::cin,line)) { 
     if(line.empty()) 
      continue; 

     using codecvt = usable_facet<std::codecvt_byname<wchar_t,char,std::mbstate_t>>; 
     std::wstring_convert<codecvt> convert(new codecvt(line)); 

     for(auto const &s : args) { 
      try { 
       convert.to_bytes(s); 
      } catch (std::range_error &e) { 
       convert_failures++; 
       std::cout << line << " : " << u8cvt.to_bytes(s) << '\n'; 
      } 
     } 
    } 

    std::cout << std::string(80,'=') << '\n'; 
    std::cout << convert_failures << " wstring_convert to_bytes failures.\n"; 
} 

Вот некоторые примеры правильного вывода

en_US.ISO8859-1 : € 
en_US.US-ASCII : ✈ 

Вот пример вывода, не ожидается

en_US.ISO8859-15 : € 

Символ евро существует в ISO 8859-15 и кодировкой поэтому это не должно терпеть неудачу.

Ниже приведены примеры вывода, что я ожидаю, но не получают

en_US.ISO8859-15 : ¤ 
en_US.US-ASCII : ¤ 

Это символ валюты, которая существует в ISO 8859-1, но был удален и заменен символом евро в ISO 8859-15. Это преобразование не должно преуспевать, но сигнализация не сигнализируется. Изучая этот случай, я обнаружил, что в обоих случаях «¤» преобразуется в 0xA4, что является представлением ISO «8859-1» «¤».

Я не использую xlocale напрямую, только косвенно через libC++. Является xlocale на Mac OS X просто сломанной с плохими определениями локали? Есть ли способ исправить это? Или проблемы, которые я вижу в результате чего-то еще?

ответ

3

Я подозреваю, что вы видите проблемы с системой xlocale. A bug report был бы очень благодарен!

+2

сделано. id 10935025 – bames53

+0

По-прежнему выглядит сломанным в 10.8 :(Может быть, есть какой-то способ получить данные xlocale и вручную взломать исправление? – bames53

+0

Оказывается, UTF-32 на самом деле не используется как кодировка wchar_t всеми локалями на OS X , что довольно неудачно. – bames53

-1

Я не знаю, почему вы ожидаете, что wchar_t будет UTF-32, или где вы слышали, что «соглашение OS X о том, что wchar_t является UTF-32». Это, безусловно, неверно. wchar_t имеют ширину всего 16 бит.

См. http://en.wikipedia.org/wiki/Wide_character для получения дополнительной информации о wchar_t.

+3

'wchar_t' - 32 бит в ширину в OS X и большинстве операционных систем Unix, а не 16. – bames53

+1

... факт, который Wikipedia упоминает, наряду с лакомым кусочком, что он также может быть 8 бит на других платформах. C + +11 добавляет 'char16_t' и' char32_t', чтобы решить эту проблему, но это не связано. – Potatoswatter