Skip to main content
GameDev.net gamedev.net
🔒 Locked

using sscanf

Started by Buzz1982 Jul 3, 2009 at 6:08 AM 6 replies 1.1k views
Original Post
Buzz1982
Buzz1982
Hello, I am using sscanf function in c++. I am unable to understand completely how it functions. I am reading some values from a string using sscanf. However, I am not getting the desired result. Let me show some examples, sscanf(row, "%s%f%*[ \t]%c%*[ \t]%f%s", &label, &low, &dummy, &high, &unit); The above line works fine when 'row' string is "AF 870 - 950Mhz", ie it fill as follows, label = AF low = 870 dummy = '-' high = 950 unit = Mhz However, in case where 'row' string is "AF 870-950Mhz", it doesn't read correctly. Can you please tell me what is wrong with my code. It seems that my understanding of this function is not correct. Thank you Best Regards.
ddlox
ddlox
msdn says:
Quote:

An input field is defined as all characters up to the first white-space character (space, tab, or newline), or up to the first character that cannot be converted according to the format specification, or until the field width (if specified) is reached.

but the important part is here:
Quote:

If there are too many arguments for the given specifications, the extra arguments are evaluated but ignored.


And this is what is happening in the case row = 'AF 870-950Mhz'
===> label = AF
===> low = 870
===> the rest from '-' will be read but ignored because it cannot be interpreted into a float.

DevFred
DevFred
Quote:
Original post by Buzz1982
I am using sscanf function in c++.

Why don't you use real C++ tools?

#include <sstream>#include <string>void scan(std::string const& str){    std::string label;    int low;    char dummy;    int high;    std::string unit;    std::stringstream ss(str);    ss >> label >> low >> dummy >> high >> unit;        std::cout << label << std::endl;    std::cout << low << std::endl;    std::cout << high << std::endl;    std::cout << unit << std::endl;}int main(){    scan("AF 870 - 950MHz");    scan("AF 870-950MHz");}

DevFred
DevFred
Or even better, write a class that represents those things you are processing.

#include <iostream>#include <sstream>#include <stdexcept>#include <string>class Component{    std::string label_;    int low_;    int high_;    std::string unit_;public:    Component() : low_(0), high_(0) {}    Component(std::string const& str)    {        std::stringstream ss(str);        ss >> *this;    }    friend std::ostream& operator<<(std::ostream& os, Component const& comp)    {        os << comp.label_ << ' ' << comp.low_ << '-' << comp.high_ << ' ' << comp.unit_;        return os;    }    friend std::istream& operator>>(std::istream& is, Component& comp)    {        Component temp;        char dummy;        is >> temp.label_ >> temp.low_ >> dummy >> temp.high_ >> temp.unit_;        if (!is) throw std::invalid_argument("parse error");        if (temp.low_ > temp.high_) throw std::invalid_argument("invalid range");        comp = temp;        return is;    }    // only define the getters you really need    std::string const& label() const    {        return label_;    }    int low() const    {        return low_;    }    int high() const    {        return high_;    }    std::string const& unit() const    {        return unit_;    }};int main(){    try    {        Component x("AF 870 - 950MHz");        std::cout << x << std::endl;        Component y("1234567 AF 870-950MHz");        std::cout << y << std::endl;    }    catch (std::exception& e)    {        std::cout << e.what() << std::endl;    }}

Now you can directly read those things from files because the >> operator is overloaded for it.
Buzz1982
Buzz1982
Thanks a lot for the help. DevFred! do you know if there is any way to know that the following operation has filled in all the variables?

ss >> label >> low >> dummy >> high >> unit;

What I mean to say is, what if the string does not contain low, high or unit values? Is there any way to know how many variables are filled correctly.

For example sscanf return this number that how many variables are correctly filled in the given variables.

Thanks for your help again.

Best Regards.
Zakwayda
Zakwayda
Quote:
Original post by Buzz1982
Thanks a lot for the help. DevFred! do you know if there is any way to know that the following operation has filled in all the variables?

ss >> label >> low >> dummy >> high >> unit;

What I mean to say is, what if the string does not contain low, high or unit values? Is there any way to know how many variables are filled correctly.

For example sscanf return this number that how many variables are correctly filled in the given variables.

Thanks for your help again.

Best Regards.
The C++ stream classes have some flags you can check to determine their state; they also offer an implicit conversion that allows you to use them where a Boolean expression is expected. So for example, you can check the stream's state following an extraction like this:
s >> x >> y >> z;if (!s) {    // Do something...}
Check the docs for more info.
DevFred
DevFred
You can read one thing at a time and check the status of the stream after each try.
ss >> label;if (!ss) there_was_a_problem;ss >> low;if (!ss) there_was_a_problem;ss >> dummy;if (!ss) there_was_a_problem;ss >> high;if (!ss) there_was_a_problem;ss >> unit;if (!ss) there_was_a_problem;
erissian
erissian
int result = sscanf(row,"%s%f%[^0-9]%f%s",label,&low,dummy,&high,unit);


%s will process the label until it comes across whitespace.
%f will ignore everything until it finds something that could be interpreted as a floating point number.

%[] is wonderful in that it denotes a list of characters that are acceptable input.

%[ABCDEF] will read in a string that contains only these 6 characters, and stop when it comes across something else.

It also accepts ranges:
%[A-F] does the same as above.

%[!@u-z ] would accept the characters '!' '@' 'u' 'v' 'w' 'x' 'y' 'z' and ' '.

You can invert the selection with ^, so

%[^A-Za-z] would process everything that isn't a letter.

In this case, I used %[^0-9] for the separator, which will throw out all input until it reaches a number.
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.