将浮点数转换为纯字符串表示

2022-01-15 00:00:00 floating-point format php regex-almighty

所以,

问题

我的问题是关于琐碎的事情:如何将数字字符串转换为它的普通(本机")表示.这意味着:如果数字字符串已经在普通视图中,则保持原样,但如果它是科学计数法,则将其转换.示例:

<上一页>"3" --> "3""1.5" --> "1.5"-15.482E-2" --> -0.15482"

数字字符串应该是有效的,如果不是 - 那么它不是转换的情况(例如,我们可以自由地返回 null 或空字符串).

用例

这对于 bcmath 是必需的,因为它不能用于科学浮点数.因此,它们需要转换为纯字符串(问 这里).这个用例的重要结果是数字字符串可以是 1E-3001E+500 之类的东西.由于我们正在使用 bcmath - 它的目的是处理这些事情.

我的方法

目前,我已经通过 正则表达式全能,例如:

函数 parseFloat($string){$string = (string)$string;if(preg_match('/^[+-]?(d+|d+.d*)[Ee]([+-]?)(d+)$/', $string, $matches)){$precision = false!==($dot=strpos($matches[1], '.'))?strlen($matches[1])-$dot-1:0;$precision = $matches[2]=='-'?$precision + (int)$matches[3]:$precision - (int)$matches[3];return number_format($string, $precision<0?0:$precision, '', '');}if(preg_match('/^[+-]?(d+|d+.d+)$/', $string)){返回$字符串;}}

问题

我觉得应该有更简单和更明智的方法来做到这一点.如何在 PHP 中以更简单的方式实现这一点?可能是一些棘手的 sprintf() 格式?

重要提示:我不想处理精度问题.我要黑匣子.在那里传递一些数字 - 得到字符串作为输出.就这样.不想处理其他任何事情.事实上,我所有的正则表达式都是关于计算长度和精度 - 所以,当然,如果明确地传递它们(例如作为参数) - 我们会摆脱正则表达式.但是 - 不,这不是我想要的.

解决方案

因为 sprintf()"%.f" 等表达式有问题"1e-8",可能需要一些文字处理:

函数 convertFloat($floatAsString){$norm = strval(floatval($floatAsString));if (($e = strrchr($norm, 'E')) === false) {返回$标准;}返回 number_format($norm, -intval(substr($e, 1)));}

测试:

3 31.5 1.5-15.482e-2 -0.154821e-8 0.000000011e+3 1000-4.66E-2 -0.04663e-3 0.003

SO,

The problem

My question is about trivial thing: how to convert numeric string to it's plain ("native") representation. That means: if numeric string is already in plain view, leave it as it is, but if it is in scientific notation, convert it. Sample:

"3"          -->  "3"
"1.5"        -->  "1.5"
"-15.482E-2" -->  "-0.15482"

Numeric string supposed to be valid, and if it's not - then it's not a case for conversion (we're free to return null or empty string, for example).

Use-case

That is needed for bcmath because it can't work with scientific floats. Thus, they need to be converted to plain strings (asked here). So important consequence from this use-case is that numeric string can be something like 1E-300 or 1E+500. Since we're working with bcmath - it's intention is to handle such things.

My approach

For now, I've implemented that with regex-almighty, like:

function parseFloat($string)
{
   $string = (string)$string;
   if(preg_match('/^[+-]?(d+|d+.d*)[Ee]([+-]?)(d+)$/', $string, $matches))
   {
      $precision = false!==($dot=strpos($matches[1], '.'))
                   ?strlen($matches[1])-$dot-1
                   :0;
      $precision = $matches[2]=='-'
                   ?$precision + (int)$matches[3]
                   :$precision - (int)$matches[3];
      return number_format($string, $precision<0?0:$precision, '', '');
   }
   if(preg_match('/^[+-]?(d+|d+.d+)$/', $string))
   {
      return $string;
   }
}

The question

I feel that there should be more simple and wise way to do that. How to achieve that in more simple way in PHP? May be some tricky sprintf() format?

Important note: I don't want to deal with precision. I want black box. Pass something numeric there - got string as output. That's all. Don't want to deal with anything else. In fact, all my regex are about calculating length & precision - so, sure, if pass them explicitly (as parameters, for example) - we cat get rid of regex. But - no, that's not what I want.

解决方案

Because sprintf() with "%.f" has trouble with expressions such as "1e-8", some text processing may be required:

function convertFloat($floatAsString)
{
    $norm = strval(floatval($floatAsString));

    if (($e = strrchr($norm, 'E')) === false) {
        return $norm;
    }

    return number_format($norm, -intval(substr($e, 1)));
}

Tested with:

3          3
1.5        1.5
-15.482e-2 -0.15482
1e-8       0.00000001
1e+3       1000
-4.66E-2   -0.0466
3e-3       0.003

相关文章