How do I handle European style float parsing?

T

trant

I have a program which parses float values from a file. European users are
getting an error because their floats use commas instead of dots.

How can I make this universal, so whether it is a dot or comma my program
will not crash?

Also, if I wrote floats back to the file, how do I handle it universally?

I am really hoping there is some easy way to do this and dont have to have
if then code branches...
 
P

Peter Duniho

trant said:
I have a program which parses float values from a file. European users are
getting an error because their floats use commas instead of dots.

How can I make this universal, so whether it is a dot or comma my program
will not crash?

It's easy to keep your program from crashing. Just check for the error
instead of letting it take your program down.

As far as handling the format goes, that really depends on how lenient
you want to be. One approach would be to always replace commas with
periods before trying to parse the data. But that obviously assumes the
input string will _always_ use _either_ commas or periods for decimal
separators, and will have _no_ other separators (e.g. thousands).

An alternative approach would be to allow the user to specify the
culture for the file by name, so that you can use the appropriate
culture during parsing (using a parse overload that allows you to pass
the culture in).

Yet another alternative would be to just ask the user "commas or
periods" and choose your parsing based on that (this may require using
TryParseExact() so you can supply an exact format...that may or may not
work well with the data as it's formatted in the file, but is certainly
worth a try).

Of course, you don't say what the source of the file is. But if it's
emitted only by your own code, you could simply always write the file
using the InvariantCulture culture, or you could write the name of the
culture into the file somewhere so that you know what culture to use
when parsing it (the former being preferable for files intended only for
machine consuption, the latter probably being preferable if you expect
humans to be reading the file).
Also, if I wrote floats back to the file, how do I handle it universally?

That depends entirely on what other consumers of the file you expect
there to be and how much control you have over the file format.
I am really hoping there is some easy way to do this and dont have to have
if then code branches...

You certainly should be able to do it without an effusion of if/then
statements.

Unfortunately, without more specifics about the source of the data and
how you want it to be used, I can't offer much more than the above.

Pete
 
T

trant

Nevermind friends, I found out the answer later.

I needed to do:

float.Parse(
val,
System.Globalization.NumberStyles.AllowDecimalPoint,
System.Globalization.CultureInfo.InvariantCulture
);
 
P

Peter Duniho

trant said:
Nevermind friends, I found out the answer later.

I needed to do:

float.Parse(
val,
System.Globalization.NumberStyles.AllowDecimalPoint,
System.Globalization.CultureInfo.InvariantCulture
);

That's not consistent with the question you asked. But, whatever.
 
G

Göran Andersson

trant said:
Nevermind friends, I found out the answer later.

I needed to do:

float.Parse(
val,
System.Globalization.NumberStyles.AllowDecimalPoint,
System.Globalization.CultureInfo.InvariantCulture
);

That will still not parse floats that were written with a culture
setting that uses comma as decimal separator.

The AllowDecimalPoint value may be a bit misleading, what it does is to
allow a decimal separator in the string, the decimal separator is
specified in the number style (culture).

The invariant culture uses a period as decimal separator, it doesn't
allow either a comma or a period as separator.


You might want to consider using the round-trip format for writing the
floats to the file:

file.Write(number.ToString("R", CultureInfo.InvariantCulture));

This will ensure that the value will be exactly the same when it's parsed.
 
K

Kalasen Zyphurus

It is precisely consistent with the question asked. You would think no one would ever need to read and write data to their own text files, without regional differences mucking it up. That last bit of code almost worked for me. It successfully got through one, but failed when it hit a negative number. More than I've gotten from any of you, talking about asking the user about regionality and such, when the opening post clearly says that he/she is just trying to read data from a file without these problems.

What I was doing at first worked simply like so: There is a .txt file where my data is kept. Like "materials.txt" for example. The program reads in the data line by line, and looks for tags. So the line "[DENSITY] 7.874" tells the program it needs to work on the density variable. (Because line.StartsWith("[DENSITY]").) It clips off that tag, and simply has a string named 'line' with the data I need, "7.874".

However, a lot of users that I assume are not in America or have weird settings are having problems at the specific line of "density = float.Parse(line);". One user manually edited the text file to replace all periods with commas, and it worked on his system. So the issue is that float.Parse is autocorrecting by region, and no one seems to be able to have a simple way of telling it not to change by region.

There's System.Globalization.CultureInfo.InvariantCulture. And wow is that a long one. But the problem there is that NOW it's having a problem reading floats with a negative sign. The furthest any of this has helped, even though it still doesn't work. So I'll tell you what I did.

That "density = float.Parse(line);" line, and in fact every time I read in a float, is wrapped in a try-catch block. I hate using those for regular control, but it's the only good way I can think of to do this. If the first try fails, the catch block attempts "density = float.Parse(DecimalSwitch(line));", where DecimalSwitch(string s) is a method I wrote. It's hackish and I hate it.

DecimalSwitch(string s) takes the string and turns it into a character array c. I then go through each character in that array and toggle it from either '.' to ',' or ',' to '.'. Not with a foreach loop because foreach loops don't like you actually doing anything to the data you're working with. I have to manually get the length of the array and do a regular for loop using that because for loops don't care until they actually hit a problem where they can't continue. Anyway, once all the ',' and '.' are toggled, it returns the character array as a string.

I know I sound angry, but I've just wasted yet another hour of dev time because apparently it isn't a problem common enough for people to come out and say clearly how to fix it, and instead complain about the answers that come close to doing something. Programming in C# by the way.
I have a program which parses float values from a file. European users are
getting an error because their floats use commas instead of dots.

How can I make this universal, so whether it is a dot or comma my program
will not crash?

Also, if I wrote floats back to the file, how do I handle it universally?

I am really hoping there is some easy way to do this and dont have to have
if then code branches...
it is easy to keep your program from crashing. Just check for the error
instead of letting it take your program down.

As far as handling the format goes, that really depends on how lenient
you want to be. One approach would be to always replace commas with
periods before trying to parse the data. But that obviously assumes the
input string will _always_ use _either_ commas or periods for decimal
separators, and will have _no_ other separators (e.g. thousands).

An alternative approach would be to allow the user to specify the
culture for the file by name, so that you can use the appropriate
culture during parsing (using a parse overload that allows you to pass
the culture in).

Yet another alternative would be to just ask the user "commas or
periods" and choose your parsing based on that (this may require using
TryParseExact() so you can supply an exact format...that may or may not
work well with the data as it is formatted in the file, but is certainly
worth a try).

Of course, you do not say what the source of the file is. But if it is
emitted only by your own code, you could simply always write the file
using the InvariantCulture culture, or you could write the name of the
culture into the file somewhere so that you know what culture to use
when parsing it (the former being preferable for files intended only for
machine consuption, the latter probably being preferable if you expect
humans to be reading the file).


That depends entirely on what other consumers of the file you expect
there to be and how much control you have over the file format.


You certainly should be able to do it without an effusion of if/then
statements.

Unfortunately, without more specifics about the source of the data and
how you want it to be used, I cannot offer much more than the above.

Pete
 
T

Tom Shelton

It is precisely consistent with the question asked. You would think no one
would ever need to read and write data to their own text files, without
regional differences mucking it up. That last bit of code almost worked for
me. It successfully got through one, but failed when it hit a negative
number. More than I've gotten from any of you, talking about asking the user
about regionality and such, when the opening post clearly says that he/she is
just trying to read data from a file without these problems.

What I was doing at first worked simply like so: There is a .txt file where
my data is kept. Like "materials.txt" for example. The program reads in the
data line by line, and looks for tags. So the line "[DENSITY] 7.874" tells
the program it needs to work on the density variable. (Because
line.StartsWith("[DENSITY]").) It clips off that tag, and simply has a string
named 'line' with the data I need, "7.874".

However, a lot of users that I assume are not in America or have weird
settings are having problems at the specific line of "density =
float.Parse(line);". One user manually edited the text file to replace all
periods with commas, and it worked on his system. So the issue is that
float.Parse is autocorrecting by region, and no one seems to be able to have
a simple way of telling it not to change by region.

There's System.Globalization.CultureInfo.InvariantCulture. And wow is that a
long one. But the problem there is that NOW it's having a problem reading
floats with a negative sign. The furthest any of this has helped, even though
it still doesn't work. So I'll tell you what I did.

That "density = float.Parse(line);" line, and in fact every time I read in a
float, is wrapped in a try-catch block. I hate using those for regular
control, but it's the only good way I can think of to do this. If the first
try fails, the catch block attempts "density =
float.Parse(DecimalSwitch(line));", where DecimalSwitch(string s) is a method
I wrote. It's hackish and I hate it.

DecimalSwitch(string s) takes the string and turns it into a character array
c. I then go through each character in that array and toggle it from either
'.' to ',' or ',' to '.'. Not with a foreach loop because foreach loops don't
like you actually doing anything to the data you're working with. I have to
manually get the length of the array and do a regular for loop using that
because for loops don't care until they actually hit a problem where they
can't continue. Anyway, once all the ',' and '.' are toggled, it returns the
character array as a string.

I know I sound angry, but I've just wasted yet another hour of dev time
because apparently it isn't a problem common enough for people to come out
and say clearly how to fix it, and instead complain about the answers that
come close to doing something. Programming in C# by the way.

Try (you'll need to add a using for System.Globalization):

float.Parse(
val,
NumberStyles.Float,
CultureInfo.InvariantCulture
);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top