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 string
s 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);
}