提问人:A1t 提问时间:8/17/2022 更新时间:8/17/2022 访问量:429
如何在 PHP (json_encode) 中禁用 0.000005 等值的科学记数法?
How to disable scientific notation for values like 0.000005 in PHP (json_encode)?
问:
我正在尝试与某些合作伙伴 API 集成。
他们只接受金额为 float 类型的 json。
例:
- 还行
{"amount":0.0000005}
- 错误
{"amount":"0.0000005"}
{"amount":5.0E-7}
如果该值大于或等于 1,则始终是 OK 方案。但就我而言,我的值> 0,< 1。
代码示例:
$arr = ['amount' => 0.0000005];
$str = json_encode($arr);
echo $str;
输出:
{"amount":5.0e-7}
我希望输出如下所示:
{"amount":0.0000005}
在php中可能吗?可能是一些技巧和窍门?
答:
0赞
Markus Zeller
8/17/2022
#1
保持它的唯一方法是将其转换为字符串。但是,它不再是一个数字了!
$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}
1赞
IMSoP
8/17/2022
#2
我能想到的最干净的方法是遍历数据,递归地用占位符替换小数字;然后,在 JSON 编码后,将最终 JSON 字符串中的占位符替换为所需格式的数字。
令人惊讶的困难部分是格式化浮点数本身;我发现这个关于如何通过一些工作但不是很优雅的实现来做到这一点的现有问题。为简洁起见,我将该部分作为待办事项保留在下面。
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
]
}
}
评论