Search Unity

Bug TMPro input field - problem with parsing integer value from string to number

Discussion in 'UGUI & TextMesh Pro' started by koZis, Feb 1, 2024.

  1. koZis

    koZis

    Joined:
    Jun 1, 2017
    Posts:
    8
    Hello,
    When I tried to parse numerical value from TMPro input text field and I received an error below. I tried to lock the input field as integer, disabled rich text, but it didn't help. Unity 2022.3.10f1, TMPro 3.0.6.

    Code (CSharp):
    1. int value = int.Parse( textfield.text );
    Error message:
    FormatException: Input string was not in a correct format.
    System.Number.ThrowOverflowOrFormatException (System.Boolean overflow, System.String overflowResourceKey) (at <787acc3c9a4c471ba7d971300105af24>:0)
    System.Number.ParseInt32 (System.ReadOnlySpan`1[T] value, System.Globalization.NumberStyles styles, System.Globalization.NumberFormatInfo info) (at <787acc3c9a4c471ba7d971300105af24>:0)
    System.Int32.Parse (System.String s) (at <787acc3c9a4c471ba7d971300105af24>:0)

    After investigation I found out that output text contains ascii character 8203 which is "Zero Width Space" attached at the end of output string, which is invisible in console. So I fixed it by trimming last character this way:

    Code (CSharp):
    1. string str = textfield.text[ ..^1 ];
    2. int value = int.Parse( str );
    I don't know why is character like this contained there, but it is not so friendly output of input field which is locked to integer.
     
    Egad_McDad and CodeRonnie like this.
  2. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    530
    Note that when you slice a string variable with a range indexer it will not create a ReadOnlySpan<char>. You are creating a whole new string object for garbage collection when you don't convert the string to a span first.
    https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1831

    Here are two ways to avoid that.
    Code (CSharp):
    1. if(!int.TryParse(textfield.text.AsSpan()[..^1], out int value))
    2.     // Respond to parse failure.
    3.  
    4. if(!int.TryParse(textfield.text.AsSpan(0, textfield.text.Length-1), out int value))
    5.     // Respond to parse failure.
    I'm not 100% sure off the top of my head which one is more performant without looking at benchmarks, but they are probably essentially equally. That's not always the case with every combination of conversion to span, using constructor arguments to slice, using range indexers to slice, or using the Slice() method, but I would have to run tests to know if one is better. The difference is usually in nanoseconds, if anything though, so ultra-micro-optimization territory.
     
    koZis likes this.