我正在尝试与一些合作伙伴API集成。
他们只接受浮点数类型的json。
示例:
- OK
{"amount":0.0000005}
- 错误
{"amount":"0.0000005"}
{"amount":5.0E-7}
如果值大于或等于1,那么情况总是可以的。但在我的情况下,我有价值观>0和<1.
代码示例:
$arr = ['amount' => 0.0000005];
$str = json_encode($arr);
echo $str;
输出:
{"amount":5.0e-7}
我希望输出看起来像这样:
{"amount":0.0000005}
这在php中可能吗?可能是一些黑客&技巧?
我能想到的最干净的方法是遍历数据,用占位符递归地替换小数字;然后,在JSON编码后,将最终JSON字符串中的占位符替换为所需格式的数字。
令人惊讶的困难部分是格式化浮动本身;我发现了一个现有的问题,即如何使用一些有效但不太优雅的实现来做到这一点。为了简洁起见,我将该部分作为TODO留在下面。
class JsonMangler
{
private const THRESHOLD = 0.0001;
private const PLACEHOLDER = '__PLACEHOLDER__';
private array $mangledData = [];
private array $substitutions = [];
private int $placeholderIncrement = 0;
public function __construct(array $realData) {
// Start the recursive function
$this->mangledData = $this->mangle($realData);
}
private function mangle(array $realData): array {
$mangledData = [];
foreach ( $realData as $key => $realValue ) {
if ( is_float($realValue) && $realValue < self::THRESHOLD) {
// Substitute small floats with a placeholder
$substituteValue = self::PLACEHOLDER . ($this->placeholderIncrement++);
$mangledData[$key] = $substituteValue;
// Placeholder will appear in quotes in the JSON, which we want to replace away
$this->substitutions[""$substituteValue""] = $this->formatFloat($realValue);
}
elseif ( is_array($realValue) ) {
// Recurse through the data
$mangledData[$key] = $this->mangle($realValue);
}
else {
// Retain everything else
$mangledData[$key] = $realValue;
}
}
return $mangledData;
}
/**
* Format a float into a string without any exponential notation
*/
private function formatFloat(float $value): string
{
// This is surprisingly hard to do; see https://stackoverflow.com/q/22274437/157957
return 'TODO';
}
public function getJson(int $jsonEncodeFlags = 0): string
{
$mangledJson = json_encode($this->mangledData, $jsonEncodeFlags);
return str_replace(array_keys($this->substitutions), array_values($this->substitutions), $mangledJson);
}
}
使用此实现对formatFloat
进行以下测试:
$example = [
'amount' => 1.5,
'small_amount' => 0.0001,
'tiny_amount' => 0.0000005,
'subobject' => [
'sub_value' => 42.5,
'tiny_sub_value' => 0.0000425,
'array' => [
1.23,
0.0000123
]
]
];
echo (new JsonMangler($example))->getJson(JSON_PRETTY_PRINT);
结果如下:
{
"amount": 1.5,
"small_amount": 0.0001,
"tiny_amount": 0.0000005,
"subobject": {
"sub_value": 42.5,
"tiny_sub_value": 0.0000425,
"array": [
1.23,
0.0000123
]
}
}
将其长期保存的唯一方法是将其转换为字符串但是它不再是一个数字了
$arr = ['amount' => number_format(0.0000005, 7)];
$str = json_encode($arr);
给出
{"amount":"0.0000005"}
Javascript本身将使用科学符号:
j = {"amount":"0.0000005"};
parseFloat(j.amount);
5e-7
黑客会删除引号。
$quoteless = preg_replace('/:"(d+.d+)"/', ':$1', $str);
echo $quoteless;
将给出
{"amount":0.0000005}