Problem with locale and sscanf (ofxImGui related)

Hi,

I’m parsing a file containing this text:

Pos=60,10

The parsing code is:

float x, y;
sscanf( line, "Pos=%f,%f", &x, &y)

It takes the comma as a numeric dot and it give

x = 60.10
y = 0.0

instead of

x = 60.0
y = 10.0

I’ve found that I can put:

#include <locale.h>
setlocale(LC_NUMERIC, "C")

in my ofApp.cpp to fix it.

But I don’t know if this is a good idea, or if I must expect some problems later in other parts af my app.
I’m not familiar with the locale subject. I can tell that this is the output of the command locale in the MSYS2 MINGW 32 console:

$ locale
LANG=fr_FR.UTF-8
LC_CTYPE="fr_FR.UTF-8"
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE="fr_FR.UTF-8"
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES="fr_FR.UTF-8"
LC_ALL=

I’m using OF0.10.0 msys release, QtCreator and Windows 7.

Can you give me some advices ?
I would prefer not to change the parsing code, because it is part of ImGui, in the SettingsHandlerWindow_ReadLine function.
I’m making an app with ofxImGui (by @jvcleave) , and the problem is that ofxImGui fail to read the settings saved by the previous run of the app because of this problem.

Thanks :slight_smile:

Hi,

I recently had to do a similar chore, using strings.

So if you have

std::string parseme = “Pos=60,10”;

You can use a combination of

size_t equalpos = string.find(’=’); and size_t commapos =string.find(’,’);

Once you have the markers positions, you can build another 2 strings with the contents you want.

string first = parseme.substr(equalpos, commapos);
string second = parseme.substrcommapos, parseme.size());

Then extract the ints like

int one = ofToInt(first);
int two = ofToInt(second);

Something like this should work, untested code, adapted from my working code.

Or like you are doing, but use %d on scanf, %f scans for floats :slight_smile:

I’m mostly looking for a solution which doesn’t involve to change the parse code, because it is part of ImGui. I wonder if changing the locale is a mess, and if yes, if there is another solution.

If I decide to change the ImGui code, your code may be a solution, and I thank you for this answer @opseidon.

By the way, I’ve done some researches about parsing, and here’s some other ways to do it. Perhaps you will be interesting, for future parse chore :wink:

string s( "Pos:60,10.33" );
string name;
float x = -1.f;
float y = -1.f;

// A solution with istringstream

istringstream iss( s );
char temp;
getline( iss, name, ':' );
iss >> x >> temp >> y;

cout << "name :" << name << endl;
cout << "x :" << x << endl;
cout << "y :" << y << endl;

// A solution with regular expressions

regex re( "(.*):([\\d.]+),([\\d.]+)" ) ;
smatch match ;
regex_search( s, match, re );
name =  match.str(1);
x =  ofToFloat( match.str(2) );
y =  ofToFloat( match.str(3) );

cout << "name :" << name << endl;
cout << "x :" << x << endl;
cout << "y :" << y << endl;
1 Like

thanks! super helpful concise gather up!

yeah, i keep away from changing locales, better to go to the bare metal of the thing, makes it more portable.

:wink:

For future reference, the C++ way to set and restore the locale seems to be:

// Switch to "C" locale to parse floating points
std::locale prev_locale = std::locale::global( std::locale::classic() );

// Parse the text here

// Restore locale
std::locale::global( prev_locale );

(source)

Not tested in the context of this thread topic.