Home > Enterprise >  Weird number conversion / encoding in Unity C#
Weird number conversion / encoding in Unity C#

Time:11-03

I have this iOS project that embed an unity scene as a view. This problem occur on a device that set a localize that number has comma , as decimal seperator, rather than a point .

I sent a parameter string from native code (swift) to unity. Unity then parse the string from iOS, make a new parameters to embed in another http request.

this is the log in xcode:

param from iOS: 615d48538edef900126a784e***616957b6f59835001137ae7b***98.42519685039369***100.06561679790026
Request Object:
- distanceFromCeiling: 9,84251968503937E 15
- distanceFromSideWall: 1,000656167979E 16
  - Obj: : UpdateRequest
  - Obj.distanceFromCeiling: : 9,84251968503937E 15
  - Obj.distanceFromSideWall: : 1,000656167979E 16
DATA request {"distanceFromCeiling":9842519685039368.0,"distanceFromSideWall":10006561679790026.0}

I expected that I send 98.42519685039369, 100.06561679790026, but for some reason, it becomes 9842519685039368.0, 10006561679790026.0 in the data request json string.

How to fix this? I have another log from a different device, with localize en-US and it seems the problem doesn't occur here.

The code in Unity (search for is_the_problem_here to jump right to the quetionable line:

using System;
using System.Collections;
using System.Collections.Generic;
using Lean.Touch;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.UI;
using BestHTTP;
using System.Text;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using UnityEngine.UIElements;

public class GameManager : MonoBehaviour
{

// Other functions
// ====================================

void callApiFromIOS(string param)
{
    Debug.Log("param from iOS: "   param);

    string[] str = param.Split(new string[] { "***" }, StringSplitOptions.None);

    // is_the_problem_here
    System.Nullable <double> distanceFromCeiling = null;
    System.Nullable<double> distanceFromSideWall = null;

    if (str != null && str.Length >= 4)
    {
        string ceiling = str[2];
        if (!ceiling.Equals("null"))
        {
            // is_the_problem_here
            distanceFromCeiling = Convert.ToDouble(ceiling);
        }
       
        string sideWall = str[3];
        if (!sideWall.Equals("null"))
        {
            // is_the_problem_here
            distanceFromSideWall = Convert.ToDouble(sideWall);
        }
    }

    Debug.Log("Request Object: ");
    Debug.Log("- distanceFromCeiling: "   distanceFromCeiling);
    Debug.Log("- distanceFromSideWall: "   distanceFromSideWall);

    UpdateRequest updateRequest = new UpdateRequest(distanceFromCeiling, distanceFromSideWall);
    Debug.Log("  - Obj: : "   updateRequest);
    Debug.Log("  - Obj.distanceFromCeiling: : "   updateRequest.distanceFromCeiling);
    Debug.Log("  - Obj.distanceFromSideWall: : "   updateRequest.distanceFromSideWall);

    // is_the_problem_here
    string data = JsonConvert.SerializeObject(updateRequest);

    Debug.Log("DATA request "   data);

     // the rest of the code is set the json data as request body and send http.
}

The other log:

param from iOS: 615d48538edef900126a784e***616957b6f59835001137ae7b***98.42519685039369***100.06561679790026

Request Object: 
- distanceFromCeiling: 98.4251968503937
- distanceFromSideWall: 100.0656167979
  - Obj: : UpdateRequest
  - Obj.distanceFromCeiling: : 98.4251968503937
  - Obj.distanceFromSideWall: : 100.0656167979
DATA request {"distanceFromCeiling":98.425196850393689,"distanceFromSideWall":100.06561679790026}

** UPDATE **

I've tried following this link but it's still not working as expect (same output as the first)

var converter = new FormattedDecimalConverter(CultureInfo.GetCultureInfo("en-US"));
string data = JsonConvert.SerializeObject(updateRequest, converter);

The converter class:

using System;
using System.Globalization;
using Newtonsoft.Json;

internal class FormattedDecimalConverter : JsonConverter
{
    private CultureInfo culture;

    public FormattedDecimalConverter(CultureInfo culture)
    {
        this.culture = culture;
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(Convert.ToString(value, culture));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Sorry for being clueless. What am I doing wrong here?

** UPDATE **

so changing Convert.toDouble() to double.Parse(ceiling, CultureInfo.InvariantCulture) fix the problem. What weird issue.

CodePudding user response:

Per default Convert.ToDouble(string) uses the language/region settings of the device the code is running on.

In some cultures the . character is not considered as the decimal splitter but rather the decimal group character.

=> e.g. 1.000 is not one but rather one thousand!


If dealing with strings across multiple devices you should always make sure to use the cultured overload Convert.ToDouble(string, IFormatProvider) and pass in the CultureInfo.InvariantCulture which is based on en-us.

string ceiling = str[2];
if (!ceiling.Equals("null"))
{
    // is_the_problem_here
    distanceFromCeiling = Convert.ToDouble(ceiling, CultureInfo.InvariantCulture);
}
   
string sideWall = str[3];
if (!sideWall.Equals("null"))
{
    // is_the_problem_here
    distanceFromSideWall = Convert.ToDouble(sideWall, CultureInfo.InvariantCulture);
}
  • Related