tags:

views:

40

answers:

4

hi guys, i'd like to know if there a way to get atof continue converting to number even if there are non valid charcters in the way

for example let say i have string "444-3-3-33" i want to covert it to a double a=4443333 (and keep the string as it was) happy to get any suggestions or an alternative way

thanks!

A: 

I would recommend sscanf

[edit]

upon further review, it would seem that you'll have to use strstr as sscanf could have an issue with the embedded '-'

further, the page should give you a good start on finding (and removing) your '-' char's

[/edit]

KevinDTimm
could you elaborate how can i use it?
Nadav
ok i've read about strstr, but if i don't want to change my original string i would have to create a copy right?
Nadav
you could, or the next option is to use strtok (even better suited to your purpose and non intrusive to the original string)
KevinDTimm
A: 

copy the 'string number' to a local buffer(a std::string), then strip out the accepted chars from the number(compressing the string, as to not leave blank space, thus using std::string.replace), then call atof on std::string.c_str. alternatly you can use c strings, but then this wouldn't be C++.

alternatively, create a custom version of atof your self, using the source from say stdlibc or basic math.

Necrolis
+3  A: 

I can't take credit for this solution, though it's a good one, see this SO post. For those too lazy to skip over, the author recommends using a locale to treat all non-numeric digits as whitespace. It might be overkill for your solution but the idea is easily adaptable. Instead of all non-numeric, you could just use "-" as your whitespace. Here's his code, not mine. Please, if you like this give him the upvote.

struct digits_only: std::ctype<char> 
{
    digits_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
        return &rc[0];
    }
};

bool in_range(int lower, int upper, std::string const &input) { 
    std::istringstream buffer(input);
    buffer.imbue(std::locale(std::locale(), new digits_only()));

    int n;

    while (buffer>>n)
        if (n < lower || upper < n)
            return false;
    return true;
}

Then just remove the whitespace and pass the string to atof.

wheaties
+1 for altruistic redirection of upvotes
Steve Townsend
@Steve Townsend thanks, I'm a big believer in credit where credit due.
wheaties
+1  A: 

Both of the following strip out non-digits for me

bool no_digit(char ch) {return !std::isdigit(ch);}

std::string read_number(const std::string& input)
{
    std::string result;
    std::remove_copy_if( input.begin()
                       , input.end()
                       , std::back_inserter(result)
                       , &no_digit);
    return result;
}

std::string read_number(std::istream& is)
{
    std::string result;
    for(;;) {
        while(is.good() && !std::isdigit(is.peek()))
            is.get();
        if(!is.good())
            return result;
        result += is.get();
    }
    assert(false);
}

You can then read number using string streams:

std::istringstream iss(read_number("444-3-3-33");
int i;
if( !(iss>>i) ) throw "something went wrong!";
std::cout << i << '\n';
sbi
Rewriting the reverse of is_digit? Couldn't you use `not1` and `ptr_fun` instead?
wheaties
@wheaties: Yes, this would probably work. But then there might be implementations where `isdigit` is still a macro. (Just yesterday someone posted a question here about _beginning a new project_ with VC6.) Also, I find the current std lib's ways to bind clumsy at best. So I would have to drag boost into this small example... In the end I decided that a small function is easier.
sbi
@sbi that poor fella.
wheaties
@wheaties: I have no idea what you're trying to say.
sbi