Dart/Flutter:当将 Java Long 从 Json 字符串转换为 Dart int 时,jsonDecode() 会丢失精度

问题描述 投票:0回答:2

总结: 我正在从 Android Java 端发送一个 Json 字符串到 Flutter Dart 端。我使用 jsonDecode() 来解析 Json String,但是 Long 类型的数字会转换为 int 并失去精度。我希望 Java Long 类型在 jsonDecode() 认为它是 int 之前被解析为 Dart String 或 BigInt。

详细: 我正在编写一个 Dart 插件,它从 Android Java 代码获取 Json 字符串。在我的Android代码中,它是一个可以转换为支持Long类型的JSONObject的String。我将此字符串发送到 Dart 端。该字符串如下所示:

{
  "myList": [
    {"longNum": 1234567890123401352},
    {"longNum": 1234567890123450168},
    {"longNum": 1234567890123452213}
  ],
  "secondList": "other stuff"
}

我尝试 jsonDecode() 这个字符串以获得我的“longNum”,但似乎 jsonDecode() 会自动将其转换为 int 并且会丢失精度。

这是我的测试代码:

import 'dart:convert';

void main() {
  var a = '''{
      "myList": [
        {
          "longNum": 1234567890123401352
        },
        {
          "longNum": 1234567890123450168
        },
        {
          "longNum": 1234567890123452213
        }
      ],
      "secondList": "Other stuff... Is regex an elegant solution to parse 1234567890123401352 here?"
    }''';
  Map aMap = jsonDecode(a);
  print(aMap.toString());
}

控制台日志:

{myList: [{longNum: 1234567890123401500}, {longNum: 1234567890123450000}, {longNum: 1234567890123452200}], secondList: other stuff}

我想找到一种将 int 自动解析为 String/BigInt 的方法。 我在网上搜索但发现唯一的方法是它本来应该是一个String,然后我可以BigInt.parse()这个数字。在 Dart 方面是否还有其他方法可以将其解析为 String 或 BigInt 类型,而不会让 jsonDecode() 认为它是一个 int ?比如将 jsonDecode(myStr) 重写为 jsonDecode(myStr, String) ?

否则,我必须在 Android 端将此字符串转换为 JSONObject 并将 int 修改为 String,然后将 JSONObject.toString() 发送到 Dart。我想如果以后我从另一端得到一个 json 字符串,就像来自服务器的 API 调用一样,那么它可能不再起作用了。因此我想知道在Dart方面是否有更好的方法。

非常感谢!

json dart long-integer
2个回答
0
投票

我希望 Java Long 类型在 jsonDecode() 认为它是 int 之前被解析为 Dart String 或 BigInt。

这不是

jsonDecode
所做的。它将 JSON 数字解码为 Dart 数字。

如果你想以不同的方式解析,你必须自己解析 JSON,或者用字符串替换文字(你可以使用 RegExp 用引号将数字括起来)before 使用

jsonDecode
进行解析。

但是,如果您在本机平台上运行,则不应该需要,因为 Dart

int
是一个 64 位数字,就像 Java
long
一样, 并且您的示例中的数字应该被正确解析。

您的问题表明您正在网络上运行,其中所有 Dart 数字都是 JavaScript 数字(这意味着

double
s),最多具有 53 位精度。 Web Dart 编译使用 JavaScript
JSON.parse
,因此它可以完成 JavaScript 的工作。

在这种情况下,也许将大数字转换为字符串是个好主意。 也许:

final _jsonLiterals = RegExp(
    r'"(?:[^"\\]|\\.)*"|((?<![eE.\d+\-])[+\-]?\d{16,}(?![\d.eE]))');
String quoteBigInts(String jsonSource) =>
  jsonSource.replaceAllMapped(_jsonLiterals, (m) {
    var digits = m[1];
    if (digits != null) return '"$digits"';
    return m[0]!;
  });

0
投票

您可以尝试这个解决方案。
这是一个 json 解析器和用于后处理的钩子。

import 'package:parser_combinator/extra/json_parser.dart' as json_parser;
import 'package:parser_combinator/parser_combinator.dart';
import 'package:parser_combinator/parsing.dart';
import 'package:parser_combinator/runtime.dart';
import 'package:parser_combinator/tracing.dart';

void main(List<String> args) {
  bool fastParse<O>(Parser<String, O> parser, State<String> state) {
    return parser.fastParse(state);
  }

  String? number;
  Result<O>? parse<O>(Parser<String, O> parser, State<String> state) {
    final pos = state.pos;
    final result = parser.parse(state);
    if (parser.name == '_number') {
      if (result != null) {
        number = state.input.substring(pos, state.pos);
      }
    } else if (parser.name == '_value') {
      if (number != null) {
        final value = number;
        number = null;
        // Or use BigNum here...
        return Result(value as O);
      }
    }

    return result;
  }

  final builder = TracerBuilder(
      fastParse: fastParse,
      parse: parse,
      filter: <O>(parser) {
        return parser.name == '_number' || parser.name == '_value';
      });
  final p = builder.build(json_parser.parser);
  const input = '''{
      "myList": [
        {
          "longNum": 1234567890123401352123456789012340135212345678901234013521234567890123450168
        },
        {
          "longNum": 1234567890123450168
        },
        {
          "longNum": 1234567890123452213
        }
      ],
      "secondList": "Other stuff... Is regex an elegant solution to parse 1234567890123401352 here?"
    }''';

  final r = parseString(p.parse, input);
  print(r);
}

输出:

{myList: [{longNum: 1234567890123401352123456789012340135212345678901234013521234567890123450168
        }, {longNum: 1234567890123450168
        }, {longNum: 1234567890123452213
        }], secondList: Other stuff... Is regex an elegant solution to parse 1234567890123401352 here?}
© www.soinside.com 2019 - 2024. All rights reserved.