Сокращение (округление) больших чисел до читаемых тыс. млн. млрд.
Задача: У нас есть большое число с кучей нулей, или может просто большое число, которое неудобно читать. Нам нужно преобразовать его в удобное для чтение число. Например, число 1500, должно превратиться в 1,5 тыс..
В WP есть подобная функция, только для преобразования байтов в килобайты, мегабайты. См. size_format().
Решение: конвертация больших чисел в текстовый вид
Код ниже преобразовывает переданное число в читаемую форму 1 тысяча, 1 миллион, 1 миллиард.
Вариант 1 (рекурсия)
/**
* Convert big number to readable format.
*
* @param int|string $num Number to format.
* @param int $decimals Optional. Precision of number of decimal places. Default: 0.
* @param string $return_type Optional. Return format. One of: `string`, `object`. Default: string.
* @param int $_depth Internal. For recursion.
*
* @return string|object Object with two elements: `num` and `unit`.
*
* @version 1.3
*/
function number_to_human( $number, int $decimals = 1, string $return_type = 'string', int $_depth = 0 ) {
static $abbrs;
$abbrs || $abbrs = [ '',
__( 'тыс.', 'hl' ),
__( 'млн.', 'hl' ),
__( 'млрд.', 'hl' ),
__( 'трлн.', 'hl' ),
__( 'квдрлн.', 'hl' )
];
if( $number >= 1000 ){
return call_user_func( __FUNCTION__, $number / 1000, $decimals, $return_type, ++$_depth );
}
$number = number_format_i18n( $number, $decimals );
$float_sign = $GLOBALS['wp_locale']->number_format['decimal_point'];
if( strpos( $number, $float_sign ) ){
$number = rtrim( $number, '0' );
$number = rtrim( $number, $float_sign );
}
$abbr = $_depth ? $abbrs[ $_depth ] : '';
if( 'string' === $return_type ){
return trim( "$number $abbr" );
}
return (object) [
'num' => $number,
'abbr' => $abbr,
];
}
$arr = [ number_to_human( 0 ), // 0 number_to_human( 120 ), // 120 number_to_human( 16 ), // 16 number_to_human( 1654, 2 ), // 1,65 тыс. number_to_human( 16504.234 ), // 16,5 тыс. number_to_human( 16504.234, 2 ), // 16,5 тыс. number_to_human( 254854564, 2 ), // 254,85 млн. ]; /* Array ( [0] => 0 [1] => 120 [2] => 16 [3] => 1,65 тыс. [4] => 16,5 тыс. [5] => 16,5 тыс. [6] => 254,85 млн. ) */
<?php $data = number_to_human( 254854564, 2, 'object' ) ?> <div class="price"> <span class="number"><?= $data->num; // 254,9 ?></span> <span class="abbr"><?= $data->abbr; // млн. ?></span> </div>
Вариант 2 (без рекурсии)
/**
* Convert big number to readable format.
*
* @param int|float|string $num Number to format.
* @param int $decimals Optional. Precision of number of decimal places. Default: 0.
*
* @return object Object with two elements: `num` and `unit`.
*
* @version 1.1
*/
function num_to_human( $num, int $decimals = 1 ) {
static $units;
$units || $units = [
'квдрлн.' => 1000 ** 5,
'трлн.' => 1000 ** 4,
'млрд.' => 1000 ** 3,
'млн.' => 1000 ** 2,
'тыс.' => 1000,
'' => 1,
];
$number = 0;
foreach( $units as $unit => $mag ){
if ( (float) $num >= $mag ) {
$number = $num / $mag;
break;
}
}
$number = number_format_i18n( $number, $decimals );
if( preg_match( '/[,.]/', $number, $match ) ){
$number = rtrim( $number, '0' );
$number = rtrim( $number, $match[0] );
}
return (object) [
'num' => $number,
'unit' => $unit
];
}
Пример использования:
Класс Объединяющий в себе несколько функций
GitHubПример использования:
GitHub<?php
class Num_FormatTest extends extends \WP_Mock\Tools\TestCase {
public function setUp(): void {
parent::setUp();
$GLOBALS['wp_locale'] = (object) [
'number_format' => [
'thousands_sep' => ' ',
'decimal_point' => ',',
],
];
\WP_Mock::userFunction( 'number_format_i18n' )->andReturnUsing( static function( $number, $decimals = 0 ) {
global $wp_locale;
return number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
} );
}
public function tearDown(): void {
unset( $GLOBALS['wp_locale'] );
parent::tearDown();
}
/**
* @covers Num_Format::human_abbr
*/
public function test__human_abbr(): void {
$this->assertSame( '0', ( new Num_Format() )->human_abbr( false ) );
$this->assertSame( '0', ( new Num_Format() )->human_abbr( null ) );
$this->assertSame( '0', ( new Num_Format() )->human_abbr( 0 ) );
$this->assertSame( '1,1', ( new Num_Format() )->human_abbr( 1.0654 ) );
$this->assertSame( '16', ( new Num_Format() )->human_abbr( 16 ) );
$this->assertSame( '1,7 тыс.', ( new Num_Format() )->human_abbr( 1654 ) );
$this->assertSame( '16,5 тыс.', ( new Num_Format() )->human_abbr( 16504.234 ) );
$this->assertSame( '16,5 тыс.', ( new Num_Format() )->human_abbr( 16504.0000234 ) );
$this->assertSame( '254,9 млн.', ( new Num_Format() )->human_abbr( 254854564 ) );
$this->assertSame( '-254,9 млн.', ( new Num_Format() )->human_abbr( -254854564 ) );
}
/**
* @covers Num_Format::human_short
*/
public function test__human_short(): void {
$this->assertSame( '16,5K', ( new Num_Format() )->human_short( 16504.0000234 ) );
$this->assertSame( '254,9M', ( new Num_Format() )->human_short( 254854564 ) );
$this->assertSame( '25,5B', ( new Num_Format() )->human_short( 25485456411 ) );
$this->assertSame( '2,5T', ( new Num_Format() )->human_short( 2548545641111 ) );
$this->assertSame( '2,5Q', ( new Num_Format() )->human_short( 2548545641111999 ) );
}
/**
* @covers Num_Format::human_k
*/
public function test__human_k(): void {
$this->assertSame( '0', ( new Num_Format() )->human_k( null ) );
$this->assertSame( '0', ( new Num_Format() )->human_k( false ) );
$this->assertSame( '0', ( new Num_Format() )->human_k( 0 ) );
$this->assertSame( '16,6kk', ( new Num_Format() )->human_k( 16565404.0000234 ) );
$this->assertSame( '254,9kkk', ( new Num_Format() )->human_k( 254856544564 ) );
$this->assertSame( '2,0000023', ( new Num_Format() )->human_k( 2.00000231, '2 smart' ) );
$this->assertSame( '2,00', ( new Num_Format() )->human_k( 2.00000231, '2 fixed' ) );
$this->assertSame( '2', ( new Num_Format() )->human_k( 2.00000231, '2 flex' ) );
$this->assertSame( '2,232', ( new Num_Format() )->human_k( 2.2317, '3 smart' ) );
$this->assertSame( '2,232', ( new Num_Format() )->human_k( 2.2317, '3 fixed' ) );
$this->assertSame( '2,232', ( new Num_Format() )->human_k( 2.2317, '3 flex' ) );
$this->assertSame( '-2,232', ( new Num_Format() )->human_k( -2.2317, '3 flex' ) );
}
/**
* @covers Num_Format::fixed
*/
public function test__fixed(): void {
$this->assertSame( '0,000', ( new Num_Format() )->fixed( 0.000111, 3 ) );
$this->assertSame( '1,011', ( new Num_Format() )->fixed( 1.0111, 3 ) );
$this->assertSame( '254,00', ( new Num_Format() )->fixed( 254 ) );
}
/**
* @covers Num_Format::smart
*/
public function test__smart(): void {
$this->assertSame( '0,00011', ( new Num_Format() )->smart( 0.0001111, 2 ) );
$this->assertSame( '1,00011', ( new Num_Format() )->smart( 1.0001111, 2 ) );
$this->assertSame( '254 854 564', ( new Num_Format() )->smart( 254854564 ) );
// zero decimal
$this->assertSame( '24', ( new Num_Format() )->smart( 23.54, 0 ) );
$this->assertSame( '24', ( new Num_Format() )->smart( 23.5, 0 ) );
$this->assertSame( '1', ( new Num_Format() )->smart( 1.2, 0 ) );
$this->assertSame( '0,9', ( new Num_Format() )->smart( 0.85, 0 ) );
$this->assertSame( '0,8', ( new Num_Format() )->smart( 0.83, 0 ) );
$this->assertSame( '0,07', ( new Num_Format() )->smart( 0.073, 0 ) );
$this->assertSame( '0,0063', ( new Num_Format() )->smart( 0.0063, 0 ) );
$this->assertSame( '0,003', ( new Num_Format() )->smart( 0.00301, 0 ) );
$this->assertSame( '0,00053', ( new Num_Format() )->smart( 0.00053, 0 ) );
$this->assertSame( '0,000063', ( new Num_Format() )->smart( 0.000063, 0 ) );
$this->assertSame( '0,0000073', ( new Num_Format() )->smart( 0.0000073, 0 ) );
$this->assertSame( '0,00000083', ( new Num_Format() )->smart( 0.00000083, 0 ) );
$this->assertSame( '0,000000093', ( new Num_Format() )->smart( 0.000000093, 0 ) );
$this->assertSame( '0,0000000013', ( new Num_Format() )->smart( 0.0000000013, 0 ) );
}
/**
* @covers Num_Format::flex
*/
public function test__flex(): void {
$this->assertSame( '16 504', ( new Num_Format() )->flex( 16504.0000234 ) );
$this->assertSame( '16 504,01', ( new Num_Format() )->flex( 16504.0100 ) );
$this->assertSame( '254 854 564', ( new Num_Format() )->flex( 254854564 ) );
}
}
--
П.С. Не редко слышу как числа называют цифрами. Например, "У него на счете большая цифра", "Цифра с шестью нулями". Не делайте так!