2

I'm developing a project in Unity where I use .CSV files to collect data to be used in the project. An important fact is that I'm developing the project with the operative system (OS) region in Spanish (Spain, international).

I use this .CSV file to list actions that I want my characters to perform in the game, such as moving from the current position to point A or stay still in the position for X seconds. In the .CSV I save the data as a string, but when I introduce it in the project I need it as a float:

  • MOVE: float Velocity, float Position.x, float Position.y, float Position.z
  • WAIT: float Time

Any of these actions are attached to an object that receives the action and it executes perfectly.

The problem came when I sent a build to Steam to validate the project and they notified me that they couldn't advance because the characters didn't move (the game worked, but nothing moved).

After many tests, I found the problem. It turns out that if the OS where the project's build is executed is in a region different from Spanish (Spain, international), for example in English (United Kingdom), the game runs but nothing moves in the times I originally programmed.

This problem comes because each region has a different decimal system, for example, in Spain the points are used to indicate the units and the commas to indicate the decimals ("1.234,24") and in England it is the opposite ("1,234.24"), so if I declare that my character will wait (WAIT) for "0,2" seconds (Spain), in an OS with English (United Kingdom) region, it will be "20" seconds, because it interprets the commas as unit separators. The same happens with MOVE actions.

In order not to have to change the region of my OS, I changed the commas to dots in the .CSV to move the problem to my region and make the necessary tests. So I could prove that if I put "3.00" (which would be 3 seconds) my OS interprets it as 3 minutes.

My question is: how could I solve this so that the timers works how I want no matter what region is the OS running?

I tried to make a manual parse from string to float by changing the dot to the comma, but I realized that even if I fixed the error in my region, it would move to another region.

Is there a way to configure the project so that it always used a specific number system independent from the OS? I mean, to understand the comma as a decimal and to use it for that purpose whatever the region is.

I tried System.Globalization.CultureInfo, but I didn't get anything (or I didn't fully understand it).

Is there a way to create a manual parser that works in any region?

Thank you very much.

Vicky Vicent
  • 1,818
  • 3
  • 11
  • 20
  • IMO, CSV should always be _comma_ separated, regardless of locale: 3.14,1.59,42.0 (looking at you, Microsoft Excel). Assuming you will keep/change your CSV in that format, I guess the problem is with the parsing, as you write in your last line, so it would be helpful if you can show some code of how you currently parse the file. – CompuChip May 05 '20 at 11:52
  • @CompuChip, no, semicolon > comma. – Sinatr May 05 '20 at 11:56
  • @CompuChip The issue isn't with separators in the file it's how numbers are represented in different cultures. Like five and a half in some cultures is 5.5 and other's it's 5,5. – juharr May 05 '20 at 11:59

2 Answers2

4

You were starting on the correct path by looking to System.Globalization. You just need to use the invariant culture—What does CultureInfo.InvariantCulture mean?—you can specify to use that when converting to strings and when parsing strings back to the required type, like:

using System.Globalization;
using System.IO;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var ci = CultureInfo.InvariantCulture;

            double x = 0.123;
            using(var sw=new StreamWriter("someFile"))
            {
                sw.Write(x.ToString(ci));
            }

            using (var sr=new StreamReader("someFile"))
            {
                string line = sr.ReadLine();
                x = double.Parse(line, ci);
            }
        }
    }
}
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
1

I think this is a string question. And I have these basic rules for strings:

  1. Do not store, retreive or transmit a value as string if you can avoid it. In processing string is the 2nd worst datatype. Only raw binary is worse. With CSV you have to use them, but a proper DB - even in prcoess - should not have such limitations.
  2. If you have to use strings for store, retreive or transmit, make sure you pick a fixed culture and string encoding on all endpoints. .NET will by default try to retreive the proper settings from windows, but you do not want to do that. One fixed setting is the goal. You really do not want to add Culture or Encoding issues to string processing
  3. Most advanced classes for data storage - like REST or XML Handlers - already deal with both issues for you. They can even deal with parsing for you. So you should prefer them over old .CSV files
Christopher
  • 9,634
  • 2
  • 17
  • 31
  • 1
    FYI, if you did not get proper Error messages, something might be wrong with your exception handling. Potentially critically wrong. I got two articles on teh thematic I link often: https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/ | https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET In your case it would have been better, had the programm crashed with a Format Exception - at least then you knew where the issue was. – Christopher May 05 '20 at 11:54
  • Really helpful and interesting ! – Adrian Efford May 05 '20 at 11:56