views:

266

answers:

3

A common international issue is the conversion of double values represented in strings. These stuff is found in a lot of areas.

Starting with csv files which are either called

comma separated

or

character separated

because sometimes they are stored like

1.2,3.4
5.6,6.4

in English regions or

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

in for example German regions.

From this background it is somehow necessary to know that most of the std:: methods are locale dependent. So in Germany they will read "1,2" as 1.2 and write it back as "1,2" but with an English OS it will read "1,2" as 1 and write it back as "1".

Because the locale is a global state of the application it is no good idea to switch it to a different setting and here we are with some problems when I have to read a German CSV file on an English machine or vice versa.

Its also hard to write code that behaves same on all machines. the c++ stream allow a locale setting per stream.

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

will allow you to initialize a stream with std:: C behavior and only replace the decimal point. This gives me the ability to ignore the thousand separator which may come in affect too. German 1000.12 may become "1.000,12" or in English "1,000.12" which will end up in complete confusion. Even replacing "," by "." will not help in this situation.

If I have to work with atof and friends I can use

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

to pimp my behavior.

So there is an awful amount of stuff just for international double behavior. Even my Visual Studio runs into problems because the German version wants to write 8,0 as version into the vcproj file while an English version wants to change it to 8.0 which definitively happened by incident because in XML it is defined to be 8.0 in all countries of the world.

So I just wanted to describe the problem a bit to ask for aspects I may have ignored. Things that I know:

  • decimal pint is locale dependent
  • thousand separator is locale dependent
  • exponent is locale dependent


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

Which country uses which setting? Maybe you can add me some interesting examples that I didn't have till now.

+3  A: 

http://en.wikipedia.org/wiki/Decimal_point#Examples_of_use

Pod
This was the page I didn't find :-)I actually looked for it on wikipedia but I didn't find the page.
Totonga
I just happened to have read it before at some point and remember it was there.
Pod
Since I read the wikipedia artikel I do not feel alone any more in germany. The world isn't as blue as I expected.
Totonga
A: 

I think you're looking for Appendix D of The C++ Programming Language. You may be interested that it is possible to have multiple locales in use at a time in a program.

Max Lybbert
+1  A: 

Don't ever use atof( s ). It's a quick & dirty shortcut for strtod( s, 0 ) without the error reporting. (Same for atoi() and strtol().)

If a function be advertised to return an error code in the event of difficulties, thou shalt check for that code, yea, even though the checks triple the size of thy code and produce aches in thy typing fingers, for if thou thinkest ’it cannot happen to me’, the gods shall surely punish thee for thy arrogance.

(Henry Spencer, "Ten Commandments for the C Programmer", Commandment #6)

DevSolar