двойное преобразование строк и локаль - PullRequest
7 голосов
/ 17 июня 2009

Распространенной международной проблемой является преобразование двойных значений, представленных в строках. Этот материал встречается во многих областях.

Начиная с CSV-файлов, которые называются

comma separated

или

character separated

потому что иногда они хранятся как

1.2,3.4
5.6,6.4

в регионах Англии или

1,2;3,4
5,6;6,4

например в регионах Германии.

Исходя из этого, каким-то образом необходимо знать, что большинство методов std :: зависят от локали. Так, в Германии они будут читать «1,2» как 1,2 и записывать обратно как «1,2», но в английской ОС он будет читать «1,2» как 1 и записывать обратно как «1».

Поскольку языковой стандарт является глобальным состоянием приложения, не рекомендуется переключать его на другой параметр; и здесь мы сталкиваемся с некоторыми проблемами, когда мне приходится читать немецкий CSV-файл на английском компьютере или наоборот.

Также сложно написать код, который ведет себя одинаково на всех машинах. Поток C ++ допускает настройку локали для каждого потока.

class Punctation : public numpunct<wchar_t>
{
public:

  typedef wchar_t char_type;
  typedef std::wstring string_type;

  explicit Punctation(const wchar_t& decimalPoint, std::size_t r = 0) : 
    decimalPoint_(decimalPoint), numpunct<wchar_t>(r)
  {
  }

  Punctation(const Punctation& rhs) : 
    decimalPoint_(rhs.decimalPoint_) 
  {
  }

protected:

  virtual ~Punctation() 
  {
  };

  virtual wchar_t do_decimal_point() const 
  { 
    return decimalPoint_; 
  }

private:

  Punctation& operator=(const Punctation& rhs);

  const wchar_t decimalPoint_;
};

...

std::locale newloc(std::locale::classic(), new Punctation(L','));
stream.imbue(newloc);

позволит вам инициализировать поток с поведением std :: C и заменить только десятичную точку. Это дает мне возможность игнорировать разделитель тысяч, что тоже может повлиять. Немецкий язык 1000.12 может стать "1.000,12"; или по-английски «1,000.12» приведёт в полное замешательство. Даже заменить "," на "." не поможет в этой ситуации.

Если мне нужно работать с atof и друзьями, я могу использовать

const char decimal_point = *(localeconv()->decimal_point);

чтобы подтянуть мое поведение.

Так что существует огромное количество вещей только для международного двойного поведения. Даже моя Visual Studio сталкивается с проблемами, потому что немецкая версия хочет записать 8,0 как версию в файл vcproj, в то время как английская версия хочет изменить его на 8.0, что определенно произошло из-за инцидента, потому что в XML он определен как 8.0 во всех страны мира.

Так что я просто хотел немного описать проблему, чтобы спросить об аспектах, которые я мог игнорировать. Вещи, которые я знаю:

  • десятичная пинта зависит от локали
  • разделитель тысяч зависит от локали
  • показатель степени зависит от локали

//                  German       English     Also known
// decimal point       ,            .            
// exponent            e/E          e/E          d/D
// thousand sep        .            ,

Какая страна использует какую настройку? Может быть, вы можете добавить мне несколько интересных примеров, которых у меня не было до сих пор.

Ответы [ 2 ]

2 голосов
/ 17 июня 2009

Никогда не используйте atof (s). Это быстрый и грязный ярлык для strtod (s, 0) без сообщения об ошибках. (То же самое для atoi () и strtol ().)

Если будет объявлена ​​функция, возвращающая код ошибки в случае затруднений, проверю этот код, да, хотя проверки в три раза больше твоего кода и у тебя болят печатающие пальцы, потому что, если ты думаешь, что это не может случиться с меня », боги обязательно накажут тебя за твое высокомерие.

(Генри Спенсер, "Десять заповедей для программиста на C", заповедь № 6)

0 голосов
/ 17 июня 2009

Я думаю, что вы ищете Приложение D из Язык программирования C ++ . Возможно, вас заинтересует возможность одновременного использования нескольких локалей в программе.

...