Search code examples
androidiosfluttercharacter-encodingflutter-web

Flutter parse unicode characters not working


I have the following string coming from my backend server \u25CF\u25CF\u25CF and when I decode it with UTF-8 it's working fine in the iOS native app, But when I try to parse it in flutter I'm not able to get the converted value. I have tried the following approaches but none worked

String converted = Utf8Decoder().convert(userName.codeUnits);
String uname = utf8.decode(userName.runes.toList());
String runes = String.fromCharCodes(Runes('$userName'));

Does anyone know how we can fix this? The real value should be 3 dots after conversion.

Update

This is json parsing code

if (response.statusCode == 200) {
        Map<String, dynamic> postResponse = response.data;
        var postsJson = postResponse["posts"];
     
        for (var postObjet in postsJson) {
          Map<String, dynamic> finalMap = Map<String, dynamic>.from(postObjet);
          Post p = Post.fromMap(finalMap);
          posts.add(p);
          
        }
}

Sample JSON Response

The Chat service we\u2019ve been paying for since our launch

Solution

  • You are starting with a string with unicode escapes and you want to end up with a string containing the actual unicode characters. This is easy if the input contains only unicode escapes as you can simply strip out the \u and parse the hex to a code point.

      final input = '\\u25CF\\u25CF\\u25CF'; // note I have to double the \ as this is source code
      var hexPoints = input.split('\\u').sublist(1);
      print(hexPoints); // [25CF, 25CF, 25CF]
    
      // convert to a string from codepoints, parsing each hex string to an int
      final result = String.fromCharCodes(
        hexPoints.map<int>((e) => int.parse(e, radix: 16)).toList(),
      );
      print(result); // dot, dot, dot
    

    The more general solution where there may be a mixture of escaped and unescaped characters is to use a regular expression that matches \xnnnn, parses the nnnn as hex and replaces it with that code point.

    String sanitize(String s) => s.replaceAllMapped(
          RegExp(r'\\u([0-9a-fA-F]{4})'),
          (Match m) => String.fromCharCode(int.parse(m.group(1)!, radix: 16)),
        );
    

    Use it like this:

    print(sanitize('ab\\u25CF\\u25CF\\u25CFcd')); //ab<dot><dot><dot>cd
    

    Finally, note that if these escaped strings are appearing inside JSON, the JSON decoder will automatically convert them.