Remova zero dígitos inúteis de decimais no PHP


163

Estou tentando encontrar uma maneira rápida de remover zero decimalsdos valores numéricos como este:

echo cleanNumber('125.00');
// 125

echo cleanNumber('966.70');
// 966.7

echo cleanNumber(844.011);
// 844.011

Existe alguma maneira otimizada de fazer isso?


4
Como seus valores são realmente strings, por que não usar simplesmente rtrim () - php.net/manual/en/function.rtrim.php - com um '0' como o segundo argumento
Mark Baker

Desculpe, eu não fui totalmente claro, eles nem sempre são cordas, eu corrijo a pergunta.
vitto

9
@ Mark Baker: essa é uma péssima abordagem, pois o número 120 será reduzido para 12
machineaddict

@machineaddict - seria se, e somente se, os valores da sequência não tivessem um ponto decimal ..... todos os citados pelo OP têm um ponto decimal.
Mark Baker

2
Em seguida, adicione um aviso em negrito na sua resposta, de que só funcionará se houver casas decimais.
precisa saber é o seguinte

Respostas:


354

$num + 0 faz o truque.

echo 125.00 + 0; // 125
echo '125.00' + 0; // 125
echo 966.70 + 0; // 966.7

Internamente, isso equivale a transmitir para flutuar com (float)$numou, floatval($num)mas acho mais simples.


45
Eu acho que isso é um truque sujo. eu não preferiria, porque o código não diz sobre seu comportamento, como floatval()está fazendo.
ESCOBAR

4
floatvalO comportamento do @ESCOBAR está retornando um float. Eu diria que usá-lo como um formatador de decimais também não é muito óbvio ou limpo.
Lafor

2
Isso é muito claro. Nossa equipe acabou de encontrar isso em nosso código, e havia três desenvolvedores intrigados por algum tempo. Eu acho que a resposta de Mark é uma alternativa melhor. É mais longo, mas sua intenção é clara.
Jfbalanc 17/04

2
@jfbalanc//COMMENT
Webinan

1
@ESCOBAR Não realmente, é um método sugerido oficialmente para typecasting ... procurar "tipo de malabarismo" na php.net
Gergely Lukacsy

101

você poderia apenas usar a floatvalfunção

echo floatval('125.00');
// 125

echo floatval('966.70');
// 966.7

echo floatval('844.011');
// 844.011

2
falha quando o separador de milhar é um ponto e a marca decimal é uma vírgula.
Munna Khan 31/03

20

Isto é o que eu uso:

function TrimTrailingZeroes($nbr) {
    return strpos($nbr,'.')!==false ? rtrim(rtrim($nbr,'0'),'.') : $nbr;
}

NB Isso assume que .é o separador decimal. Ele tem a vantagem de funcionar em números arbitrariamente grandes (ou pequenos), pois não há vazamento flutuante. Também não transformará números em notação científica (por exemplo, 1.0E-17).


isto não é uma solução segura, e se o preço não é decimal por exemplo, se desenvolvedor multiplicar o preço com um inteiro, então temos um inteiro?
amin

@alex Esta função funciona em números inteiros, flutuantes e strings.
MPEN

1
Solução perfeita como auxiliar para bcmath
Kart Av1k 10/01

17

Simplesmente adicionar +à sua variável string fará com que o typecast seja (float) e remova zeros:

var_dump(+'125.00');     // double(125)
var_dump(+'966.70');     // double(966.7)
var_dump(+'844.011');    // double(844.011)
var_dump(+'844.011asdf');// double(844.011)

13

Para todos que vêm a este site com o mesmo problema com vírgulas, altere:

$num = number_format($value, 1, ',', '');

para:

$num = str_replace(',0', '', number_format($value, 1, ',', '')); // e.g. 100,0 becomes 100


Se houver dois zeros a serem removidos, altere para:

$num = str_replace(',00', '', number_format($value, 2, ',', '')); // e.g. 100,00 becomes 100

Mais aqui: Número PHP: ponto decimal visível apenas se necessário


10

Se você deseja remover os dígitos zero antes de exibir na página ou no modelo.

Você pode usar a função sprintf ()

sprintf('%g','125.00');
//125

‌‌sprintf('%g','966.70');
//966.7

‌‌‌‌sprintf('%g',844.011);
//844.011

Obrigado, adorei esta resposta. Isso é muito útil para mim.
Sumit Kumar Gupta

9

Você deve converter seus números como carros alegóricos, o que fará isso por você.

$string = "42.422005000000000000000000000000";
echo (float)$string;

A saída disso será o que você está procurando.

42.422005


1
A transmissão flutuante também pode corromper seu número. por exemplo, (float)'0.1234567890124567890123456789'torna-se 0.12345678901246.
MPEN

8
$x = '100.10'; 
$x = preg_replace("/\.?0*$/",'',$x); 
echo $x;

Não há nada que não possa ser corrigido com uma simples expressão regular;)

http://xkcd.com/208/


1
Retira 0s significativos , como em "100". Também falha em retirar 0s "100.010".
MPEN

2
Todo mundo se afaste! $x = preg_replace("/(\.0*$)|((?<=\.\d*)0+$)/",'',$x);
Emanuel S.

5

Typecast para a float.

$int = 4.324000;
$int = (float) $int;

2

Devido a esta pergunta é antiga. Primeiro, me desculpe por isso.

A pergunta é sobre o número xxx.xx, mas, no caso de ser x, xxx.xxxxx ou separador decimal com diferença como xxxx, xxxx, pode ser mais difícil encontrar e remover dígitos zero do valor decimal.

/**
 * Remove zero digits from decimal value.
 * 
 * @param string|int|float $number The number can be any format, any where use in the world such as 123, 1,234.56, 1234.56789, 12.345,67, -98,765.43
 * @param string The decimal separator. You have to set this parameter to exactly what it is. For example: in Europe it is mostly use "," instead of ".".
 * @return string Return removed zero digits from decimal value.
 */
function removeZeroDigitsFromDecimal($number, $decimal_sep = '.')
{
    $explode_num = explode($decimal_sep, $number);
    if (is_array($explode_num) && isset($explode_num[count($explode_num)-1]) && intval($explode_num[count($explode_num)-1]) === 0) {
        unset($explode_num[count($explode_num)-1]);
        $number = implode($decimal_sep, $explode_num);
    }
    unset($explode_num);
    return (string) $number;
}

E aqui está o código para teste.

$numbers = [
    1234,// 1234
    -1234,// -1234
    '12,345.67890',// 12,345.67890
    '-12,345,678.901234',// -12,345,678.901234
    '12345.000000',// 12345
    '-12345.000000',// -12345
    '12,345.000000',// 12,345
    '-12,345.000000000',// -12,345
];
foreach ($numbers as $number) {
    var_dump(removeZeroDigitsFromDecimal($number));
}


echo '<hr>'."\n\n\n";


$numbers = [
    1234,// 12324
    -1234,// -1234
    '12.345,67890',// 12.345,67890
    '-12.345.678,901234',// -12.345.678,901234
    '12345,000000',// 12345
    '-12345,000000',// -12345
    '12.345,000000',// 12.345
    '-12.345,000000000',// -12.345
    '-12.345,000000,000',// -12.345,000000 STRANGE!! but also work.
];
foreach ($numbers as $number) {
    var_dump(removeZeroDigitsFromDecimal($number, ','));
}

2

Tenha cuidado ao adicionar +0.

echo number_format(1500.00, 2,".",",")+0;
//1

O resultado é 1.

echo floatval('1,000.00');
// 1

echo floatval('1000.00');
//1000

Você está respondendo a uma pergunta a partir de 2013.
VTodorov

3
A sua não é um problema para responder a uma pergunta de idade, se ele pode ajudar os leitores reais
Reign.85

1

Estranho, quando obtenho um número fora do banco de dados com um tipo "float" e se meu número é ex. 10000 quando eu flutuo, torna-se 1.

$number = $ad['price_month']; // 1000 from the database with a float type
echo floatval($number);
Result : 1

Testei todas as soluções acima, mas não funcionou.


1
$str = 15.00;
$str2 = 14.70;
echo rtrim(rtrim(strval($str), "0"), "."); //15
echo rtrim(rtrim(strval($str2), "0"), "."); //14.7

0

Maneira complicada, mas funciona:

$num = '125.0100';
$index = $num[strlen($num)-1];
$i = strlen($num)-1;
while($index == '0') {
   if ($num[$i] == '0') {
     $num[$i] = '';
     $i--;
   }

   $index = $num[$i];
}

//remove dot if no numbers exist after dot
$explode = explode('.', $num);
if (isset($explode[1]) && intval($explode[1]) <= 0) {
   $num = intval($explode[0]);
}

echo $num; //125.01

as soluções acima são a melhor maneira, mas se você quiser ter o seu próprio, poderá usá-lo. O que esse algoritmo faz: começa no final da string e verifica se é 0 , se for definido como string vazia e depois vai para o próximo caractere de volta até que o último caractere seja > 0



0

Essa é a minha pequena solução ... Pode ser incluída em uma classe e definir vários

private $ dsepparator = '.'; // casas decimais private $ tsepparator = ','; // mil

Isso pode ser definido pelo construtor e alterado para o idioma dos usuários.

class foo
{
    private $dsepparator;
    private $tsepparator;

    function __construct(){
        $langDatas = ['en' => ['dsepparator' => '.', 'tsepparator' => ','], 'de' => ['dsepparator' => ',', 'tsepparator' => '.']];
        $usersLang = 'de'; // set iso code of lang from user
        $this->dsepparator = $langDatas[$usersLang]['dsepparator'];
        $this->tsepparator = $langDatas[$usersLang]['tsepparator'];
    }

    public function numberOmat($amount, $decimals = 2, $hideByZero = false)
    {
        return ( $hideByZero === true AND ($amount-floor($amount)) <= 0 ) ? number_format($amount, 0, $this->dsepparator, $this->tsepparator) : number_format($amount, $decimals, $this->dsepparator, $this->tsepparator);
    }
    /*
     * $bar = new foo();
     * $bar->numberOmat('5.1234', 2, true); // returns: 5,12
     * $bar->numberOmat('5', 2); // returns: 5,00
     * $bar->numberOmat('5.00', 2, true); // returns: 5
     */

}

Então, eu criei uma classe de amostra com pequenas amostras. Melhor? =)
Paykoman

0

Esta é a minha solução. Eu quero manter a capacidade de adicionar separador de milhares

    $precision = 5;    
    $number = round($number, $precision);
    $decimals = strlen(substr(strrchr($number, '.'), 1));
    return number_format($number, $precision, '.', ',');

0

Esta é uma função simples de uma linha usando rtrim, salve o separador e o ponto decimal:

function myFormat($num,$dec)
 {
 return rtrim(rtrim(number_format($num,$dec),'0'),'.');
 }

0

Eu encontrei esta solução é a melhor:

public function priceFormat(float $price): string
{
    //https://stackoverflow.com/a/14531760/5884988
    $price = $price + 0;
    $split = explode('.', $price);
    return number_format($price, isset($split[1]) ? strlen($split[1]) : 2, ',', '.');
}

0

Simples e preciso!

function cleanNumber($num){
    $explode = explode('.', $num);
    $count   = strlen(rtrim($explode[1],'0'));
    return bcmul("$num",'1', $count);
}

0

Solução definitiva: a única maneira segura é usar o regex:

echo preg_replace("/\.?0+$/", "", 3.0); // 3
echo preg_replace("/\d+\.?\d*(\.?0+)/", "", 3.0); // 3

funcionará para qualquer caso


0

O seguinte é muito mais simples

if(floor($num) == $num) {
    echo number_format($num);
} else {
    echo $num;
}

-1
$value = preg_replace('~\.0+$~','',$value);

1
Melhoraria a qualidade da sua resposta se você fornecesse uma explicação sobre o que seu código faz e como ele resolverá a pergunta original.
Nigel Ren

@ Nikhil Gyan Concordo que esta resposta não é ótima. Sinta-se livre para fazer anotações. No entanto, eu pelo menos acho que não é ruim o suficiente para o sinalizador de muito baixa qualidade
Sam Hartman

-2

Este código removerá zero após o ponto e retornará apenas dois dígitos decimais.

$ número = 1200.0000;
str_replace ('. 00', '', number_format ($ número, 2, '.', ''));

A saída será: 1200

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.