Eliminar dígitos cero inútiles de decimales en PHP


163

Estoy tratando de encontrar una forma rápida de eliminar zero decimalsvalores numéricos como este:

echo cleanNumber('125.00');
// 125

echo cleanNumber('966.70');
// 966.7

echo cleanNumber(844.011);
// 844.011

¿Existe alguna forma optimizada de hacer eso?


44
Como sus valores son en realidad cadenas, ¿por qué no simplemente usar rtrim () - php.net/manual/en/function.rtrim.php - con un '0'? como segundo argumento
Mark Baker

Lo siento, no he sido completamente claro, no siempre son cadenas, solucioné la pregunta.
vitto

9
@ Marcos de Baker: que es un mal enfoque como el número 120 se recortará a 12
machineaddict

@machineaddict: lo haría si, y solo si, los valores de cadena no tuvieran un punto decimal ... todos los citados por el OP tienen un punto decimal.
Mark Baker

2
Luego debe agregar un aviso en negrita en su respuesta, que solo funciona si hay decimales.
machineaddict

Respuestas:


354

$num + 0 Hace el truco.

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

Internamente, esto es equivalente a lanzar para flotar con (float)$numo floatval($num)pero me parece más simple.


45
Creo que este es un truco sucio. No lo preferiría porque el código no dice sobre su comportamiento como lo floatval()está haciendo.
ESCOBAR

44
floatvalEl comportamiento de @ESCOBAR está devolviendo un flotador. Yo diría que usarlo como formateador de decimales tampoco es muy obvio o limpio.
2014

2
Esto es muy poco claro. Nuestro equipo acaba de encontrar esto en nuestro código, y tenía 3 desarrolladores desconcertados por algún tiempo. Creo que la respuesta de Mark es una mejor alternativa. Es más largo, pero su intención es clara.
jfbalanc

2
@jfbalanc//COMMENT
Webinan 01 de

1
@ESCOBAR En realidad no, es un método sugerido oficialmente para la conversión de texto ... busque "malabarismo de tipos" en php.net
Gergely Lukacsy

101

podrías usar la floatvalfunción

echo floatval('125.00');
// 125

echo floatval('966.70');
// 966.7

echo floatval('844.011');
// 844.011

2
falla cuando el separador de miles es un punto y la marca decimal es una coma.
Munna Khan

20

Esto es lo que uso:

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

NB Esto supone que .es el separador decimal. Tiene la ventaja de que funcionará en números arbitrariamente grandes (o pequeños) ya que no hay un elenco flotante. Tampoco convertirá los números en notación científica (por ejemplo, 1.0E-17).


esto no es una solución segura, ¿y si el precio no es decimal, por ejemplo, si se multiplica el precio de desarrolladores con un entero, entonces tenemos un número entero?
Amin

@alex Esta función funciona en enteros, flotantes y cadenas.
mpen

1
Solución perfecta como ayuda para bcmath
Kart Av1k

17

Simplemente agregar +a su variable de cadena hará que el encasillado (flotante) y elimine ceros:

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 los que visiten este sitio y tengan el mismo problema con los comas, cambie:

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

a:

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


Si hay que eliminar dos ceros , cambie a:

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

Más aquí: número PHP: punto decimal visible solo si es necesario


10

Si desea eliminar los dígitos cero justo antes de mostrar en la página o plantilla.

Puedes usar la función sprintf ()

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

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

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

Gracias, me encantó esta respuesta. Esto es muy útil para mi.
Sumit Kumar Gupta

9

Debes lanzar tus números como flotadores, lo que hará esto por ti.

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

La salida de esto será lo que estás buscando.

42.422005


1
El lanzamiento flotante también puede corromper tu número. por ejemplo se (float)'0.1234567890124567890123456789'convierte 0.12345678901246.
mpen

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

No hay nada que no se pueda solucionar con una simple expresión regular;)

http://xkcd.com/208/


1
Se quita 0s significativos como en "100". También falla para despojar 0s fuera "100.010".
mpen

2
¡Todos retrocedan! $x = preg_replace("/(\.0*$)|((?<=\.\d*)0+$)/",'',$x);
Emanuel S.


2

Debido a esta pregunta es vieja. Primero, lo siento por esto.

La pregunta es sobre el número xxx.xx, pero en caso de que sea x, xxx.xxxxx o un separador decimal de diferencia como xxxx, xxxx, esto puede ser más difícil de encontrar y eliminar dígitos cero del 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;
}

Y aquí está el código para la prueba.

$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

Tenga cuidado al agregar +0.

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

El resultado de esto es 1.

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

echo floatval('1000.00');
//1000

Estás respondiendo una pregunta de 2013.
VTodorov

3
No es un problema de responder a una vieja pregunta, si puede ayudar a los lectores reales
Reign.85

1

Extraño, cuando obtengo un número de la base de datos con un tipo "flotante" y si mi número es ex. 10000 cuando lo floto, se convierte en 1.

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

He probado todas las soluciones anteriores pero no funcionó.


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

0

Forma complicada pero 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

Las soluciones anteriores son la forma óptima, pero en caso de que desee tener la suya, puede usarla. Lo que hace este algoritmo comienza al final de la cadena y comprueba si es 0 , si es así, se establece en una cadena vacía y luego pasa al siguiente carácter desde atrás hasta que el último carácter sea > 0



0

Esa es mi pequeña solución ... Se puede incluir en una clase y configurar vars

private $ dsepparator = '.'; // decimales private $ tsepparator = ','; // mil

Eso puede establecerlo el constructor y cambiarlo a los usuarios lang.

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
     */

}

Así que he creado una clase de muestra con pequeñas muestras. ¿Mejor? =)
Paykoman

0

Esta es mi solución Quiero mantener la capacidad de agregar separador de miles

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

0

Esta es una función simple de una línea que usa rtrim, guardar separador y punto decimal:

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

0

Encontré que esta solución es la mejor:

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

Simple y preciso!

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

0

Solución definitiva: la única forma segura es usar regex:

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

funcionará para cualquier caso


0

Lo siguiente es mucho más simple

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

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

1
Mejoraría la calidad de su respuesta si proporcionara una explicación de lo que hace su código y cómo resolverá la pregunta original.
Nigel Ren

@Nikhil Gyan Estoy de acuerdo con que esta respuesta no es genial. Siéntase libre de ote down. Sin embargo, al menos no creo que sea lo suficientemente malo para una bandera de muy baja calidad
Sam Hartman

-2

Este Código eliminará cero después del punto y devolverá solo dos dígitos decimales.

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

La salida será: 1200

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.