0

I want to convert a std::string which I read from a csv file to a float. There are several float representations included like:

0,0728239
6.543.584.399
2,67E-02

These string should all be floats. First I used atof(), but the conversion was wrong:

2,67E-02 -> 2
6.543.584.399 -> 6.543

Then I used boost::lexical_cast<float>(), but when it comes to a float with an exponent included, it throws following exception

`terminate` called after throwing an instance of
`'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_lexical_cast> >'`
`what()`:  bad lexical cast: source type value could not be interpreted as target
Aborted

What is the best way to get all three types of strings converted to a float?

14
  • perhaps you could show us a sample input showing the various cases? Commented Oct 5, 2011 at 19:11
  • 4
    @iam_peter: what is the expected outcome? 6.543.584.399 cannot be valid at the same time as 0.0728239 Commented Oct 5, 2011 at 19:20
  • 1
    A locale is how you tell C++ "I'm using . to separate the groups of thousands, and , to separate the whole part of the fractional part." By default, C++ will use the C locale, which uses . to separate the whole part from the fractional part, and doesn't use anything to separate the groups of thousands. There's a "C++ way" of using locales ( www2.research.att.com/~bs/3rd_loc0.html ), but nobody uses it and some compilers don't implement it. The "C way" is pretty straightforward, though. Commented Oct 5, 2011 at 19:24
  • 2
    @sehe: Incorrect for European countries. They swapped our comma and decimal in numbers. Commented Oct 5, 2011 at 19:24
  • 1
    @ iam_peter: o heck. of course :) That makes a lot more sense. @MooingDuck: accidentally upvoted you comment. The point was that the specimen were inconsistent in and of themselves. There is no European locale that supports that (OT: I'm from such a European country myself :)) Commented Oct 5, 2011 at 19:31

3 Answers 3

6

scanf with the correct locale set. Seriously. Save yourself the hassle of doing it the "c++ way" in this case.

Sign up to request clarification or add additional context in comments.

3 Comments

atof() is hardly "the C++ way", and works fine once you set the current locale.
I didn't refer to atof(), but let me add that I think scanf is the way to go as atof does not tell you if it could not parse the string.
OP was attempting to use atof. You criticize him for "doing it the C++ way". You do raise a good point about atof not telling if it could not parse the string though.
5

http://www.cplusplus.com/reference/clibrary/clocale/

Notice that locale configuration affects the behavior of many functions within the standard C library: In string.h, functions strcoll and strxfrm are affected by character transformation rules. In ctype.h, all functions except for isdigit and isxdigit are affected by the extended character set selected. In stdio.h, formatted input/output operations are affected by character transformation rules and decimal-point character set in the numeric formatting settings. In time.h, the function strftime is affected by the time formatting settings. In this header, it affects the value returned by its functions setlocale and localeconv.

http://www.cplusplus.com/reference/clibrary/clocale/setlocale/

setlocale ( LC_NUMERIC, "" ); // "" is the Environment's default locale

Then you can use atof, scanf, etc correctly. However, that's the C way of doing things. The C++ way is:

float stof(const std::string& input) {
    std::stringstream ss;
    float result;
    static std::locale uselocale("") //again, "" is Environment's default locale
    ss.imbue(uselocale);
    ss << input;
    ss >> result;
    return result;
}

All compilers must accept these locales: "", "C"
MSVC accepts these locales: http://msdn.microsoft.com/en-us/library/hzz3tw78.aspx
(wait, does MSVC setlocale really not accept "en_US"?)
GCC accepts these locales: http://gcc.gnu.org/onlinedocs/libstdc++/manual/localization.html#locale.impl.c

Comments

0

This should do :

#include <sstream>
#include <iostream>
#include <algorithm>

bool isdot(const char &c)
{
    return '.'==c;
}

float to(std::string s)
{
    s.erase(std::remove_if(s.begin(), s.end(), &isdot ),s.end());
    replace(s.begin(), s.end(), ',', '.');


    std::stringstream ss(s);
    float v = 0;
    ss >> v;
    return v;
}

int main()
{
    const std::string a1("0,0728239");
    const std::string a2("6.543.584.399");
    const std::string a3("2,67E-02");

    std::cout << to(a1)<<std::endl;
    std::cout << to(a2)<<std::endl;
    std::cout << to(a3)<<std::endl;
}

See it live on coliru

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.