sharifulin ([info]sharifulin) wrote,
@ 2009-11-10 20:43:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Entry tags:ironman, perl, pretty

Perl. Форматирование чисел
Сегодня потребовалось написать функцию по форматированию чисел, приведение к читаемому виду: 1234567 => 1 234 567.
Написал следующую короткую и красивую функцию:

sub D($) {
	for (scalar reverse shift) {
		s/(\d{3})(?=\d)/$1 /g;
		return scalar reverse;
	}
}

say D 12345;
say D 123456;
say D 1234.56;
Спасибо [info]pavel_kudinov за подсказку использовать (?=pattern) positive look-ahead assertion (perlre).
Вместо этого у меня была вторая простая регекспа, которая удаляла лишний символ с конца.

Функция умеет работать и с флоатом, где количество знаков после запятой максимум 3, опять же благодаря (?=\d).

scalar reverse заставляет работать reverse в скалярном котексте при использовании в списковом контексте :)

По-моему, очень красиво получилось )))

Исходник


ЗЫ: С Павлом Кудиновым сошлись на мнении, что наверня-ка на CPAN есть модуль на несколько экранов с похожим функционалом :)


use Perl or die;

JFDI




(30 comments) - (Post a new comment)


[info]green_kakadu
2009-11-10 06:30 pm UTC (link)
>наверня-ка на CPAN есть модуль на несколько экранов с похожим функционалом

типа такого: Number::Format

(Reply to this)


[info]what_me
2009-11-10 06:42 pm UTC (link)
А что, ты книжку Perl Cookbook не читал?

(Reply to this) (Thread)


[info]pavel_kudinov
2009-11-10 06:43 pm UTC (link)
ха-ха, зачот :))) 1:1

(Reply to this) (Parent)(Thread)


[info]what_me
2009-11-10 06:45 pm UTC (link)
Я так однажды Schwartzian transform изобрел

(Reply to this) (Parent)(Thread)


[info]pavel_kudinov
2009-11-10 06:49 pm UTC (link)
)) прочитал что это ) я тоже его изобрёл ))

а ещё изобрёл карринг и кучу другой фигни )

кстати лёгкость, с которой эти "изобретения" даются - лишний раз доказывают мне, что не зря я книжки не читал и не читаю :)

всё необходимое - очевидно

(Reply to this) (Parent)


[info]sharifulin
2009-11-10 07:38 pm UTC (link)
Листал :)

(Reply to this) (Parent)


[info]sharifulin
2009-11-10 07:40 pm UTC (link)
Спасибо, буду знать)
Своё все-таки приятно )))

(Reply to this) (Parent)


[info]ali_lj
2009-11-10 07:50 pm UTC (link)
Хороший регэксп позволит обойтись без реверсов:

s/(\d)(?=((\d{3})+)(\D|$))/$1 /g

Подробности здесь: http://clubs.ya.ru/4611686018427411041/replies.xml?item_no=18

(Reply to this)


[info]andrejz
2009-11-10 07:51 pm UTC (link)
Еще есть красивый regexp в perlfaq5 perldoc -q 'commas'

Кстати, если уж пошла речь о там, то когда я не читал книжек, много-много лет назад, я делал это так

sub DigitToDigit {
my ($my, @array, $line);
$my = @_[0];
@array = split('',$my);

@array = reverse(@array);
for (my $g=0;$g<@array;$g++) {
$line .= " " if ($g % 3 == 0);
$line .= @array[$g];
}

$line =~ s/,/\0/;
$line = reverse($line);
return $line;
}

Shame :-)

(Reply to this)

зачем реверс?
[info]strangerlive
2009-11-10 08:06 pm UTC (link)
sub D($){
if ($_=shift){
s/(\d{3}(?!\d))/ $1/g;
return $_;
}
}

(Reply to this) (Thread)

Re: зачем реверс?
[info]ali_lj
2009-11-10 08:20 pm UTC (link)
D(12345678) -> "12345 678"

Красотища-то какая! :)

(Reply to this) (Parent)(Thread)

Re: зачем реверс?
[info]strangerlive
2009-11-10 08:28 pm UTC (link)
вай подловил :)

sub D($){
if ($_=shift){
1 while s/(\d)(\d{3}(?!\d))/$1 $2/g;
return $_;
}
}

(Reply to this) (Parent)(Thread)

Re: зачем реверс?
[info]sharifulin
2009-11-10 08:45 pm UTC (link)
и что?
дело в красоте кода, все ваши варианты некрасивые :)

(Reply to this) (Parent)(Thread)

Re: зачем реверс?
[info]ali_lj
2009-11-10 11:11 pm UTC (link)
Кому как, кому как...

Я б за (scalar reverse shift) лишил бы пива на неделю :)

(Reply to this) (Parent)(Thread)

Re: зачем реверс?
[info]pavel_kudinov
2009-11-11 09:24 pm UTC (link)
зачем сравнивать два средних решения если ниже есть отличное: s/(?<=\d)(?=(?:\d{3})+(?!\d))/ /g

кроме прочего оно хорошо читается, т.е. не является фином ушами а описывает саму суть того что нам и нужно сделать, как и должно быть. хороший код не тот, который достигает нужного эффекта "внезапно" в процессе выполнения, а тот, который описывает суть задачи, решая её.

(Reply to this) (Parent)


[info]itim
2009-11-10 09:46 pm UTC (link)
В русской типографике принято разделять цифры на группы, начиная только с 10 тысяч. То есть "3 456" - это неправильно. Можно со скрипом игнорить это правило, когда вывыдишь много денег в столбик :-)

(Reply to this) (Thread)


[info]pavel_kudinov
2009-11-11 09:25 pm UTC (link)
хорошее замечание

(Reply to this) (Parent)

Code like a man ;)
[info]hobohabilis
2009-11-11 04:28 am UTC (link)
А sprintf "%'.2f", 12345.67 в вашем Виндоусе не работает?

(Reply to this) (Thread)

Re: Code like a man ;)
[info]hobohabilis
2009-11-11 07:01 am UTC (link)
Кстати, внутренняя красота кода довольно часто вступает в противоречие с производительностью. Ваша функция форматирования является хорошим тому примером:
use Benchmark qw(cmpthese);

sub yours($) {
	for (scalar reverse shift) {
		s/(\d{3})(?=\d)/$1 /g;
		return scalar reverse;
	}
}


sub mine($)
{
	my $n = shift;

	my $s = abs($n) != $n;

	my $x = index($n, ".");

	$x = length($n) if $x == -1;

	substr($n, $x, 1, "," . substr($n, $x, 1)) while ($x -= 3) > $s;

	$n;
}


cmpthese(1000, {
	mine  => sub {mine rand(~0) for 1..1000},
    yours => sub {yours rand(~0) for 1..1000},
});


1;

__DATA__
        Rate yours  mine
yours 66.7/s    --  -52%
mine   140/s  111%    --

(Reply to this) (Parent)(Thread)

Re: Code like a man ;)
[info]pavel_kudinov
2009-11-11 12:12 pm UTC (link)
>Кстати, внутренняя красота кода довольно часто вступает в противоречие с производительностью

красивое всегда правильно, просто производительно не правильно там где это не красиво. производительно правильно в си - там это красиво. в перл правильно до тех пор пока красиво, как только некрасиво - значит не перл.

(Reply to this) (Parent)(Thread)

Шаманство не пройдет!
(Anonymous)
2009-11-11 02:23 pm UTC (link)
Объективными критериями оценки качества кода являются unit-тесты и benchmarking. А красота - нет. Вон, у эвенков с бушменами понятия о красоте совершенно другие. И ничего, живут себе. И, наверное, тоже программируют чего-нибудь. Обратите внимание, ниже по thread-у Никонор предлагает куда более лаконичное решение (http://sharifulin.livejournal.com/52634.html?replyto=196250), но с точки зрения производительности, оно может оказаться хуже того, что наваял Шарифулин.

(Reply to this) (Parent)(Thread)

Re: Шаманство не пройдет!
[info]pavel_kudinov
2009-11-11 02:45 pm UTC (link)
>Объективными критериями оценки качества кода являются unit-тесты и benchmarking

они являются объективными критериями оценки стабильности и производительности кода соответственно, но вовсе не качества - критерия по определению _субъективного_ и от того не поддающегося формальным оценкам.

Впрочем, в частном случае вы формально можете оказаться правы, когда для кого-то (например, для вас) - качество как субъективный параметр будет определено через производительность+стабильность (имеете право)

Увы, для меня это понятие гораздо более обширное

Брынза не бывает зелёного цвета, это вас кто-то обманул :) (c) Воланд

(Reply to this) (Parent)(Thread)

Re: Шаманство не пройдет!
[info]hobohabilis
2009-11-12 04:26 am UTC (link)
Вы поставьте себя на место потребителя, и проанализируйте, какую из предложенных функций форматирования выгоднее купить. Анонсируя свой продукт, я бы мог смело написать: "Вдвое быстрее, чем у конкурентов!". А Шарифулин с Никонором уповали бы, разве что, на православную солидарность, да убранство исходного кода.

(Reply to this) (Parent)(Thread)

Re: Шаманство не пройдет!
[info]pavel_kudinov
2009-11-12 12:39 pm UTC (link)
потребитель покупает не функцию форматирования а проект, стоимость времени разработчика сильно больше стоимости машинного времени, большинство проектов постоянно модифицируются -> потребитель выберет "православную солидарность да убранство исходного кода" если это хоть на 5% сэкономит время команды поддержки даже если придётся на 5% больше процессорного времени оплачивать.

Я успешно продаю в таком контексте свои услуги, так что не рассказывайте мне про потребителя: я последние годы гораздо больше общаюсь с живыми потребителями, чем с исходниками

(Reply to this) (Parent)(Thread)

Re: Шаманство не пройдет!
(Anonymous)
2009-11-12 02:14 pm UTC (link)
потребитель покупает не функцию форматирования а проект, стоимость времени разработчика сильно больше стоимости машинного времени, большинство проектов постоянно модифицируются...

Прошу прощения, но мне более не интересно продолжать эту дискуссию.

(Reply to this) (Parent)

Re: Code like a man ;)
[info]pavel_kudinov
2009-11-11 09:25 pm UTC (link)
вроде и в линуксе не работает

(Reply to this) (Parent)(Thread)

Re: Code like a man ;)
[info]hobohabilis
2009-11-12 04:36 am UTC (link)
-bash-3.2$ uname -srvio
'Linux 2.6.18-164.el5 #1 SMP Thu Sep 3 03:33:56 EDT 2009 i386 GNU/Linux
...

-bash-3.2$ man sprintf
...

The five flag characters above are defined in the C standard. The SUSv2 specifies one further flag character.

' For decimal conversion (i, d, u, f, F, g, G) the output is to be grouped with thousands' grouping characters if the locale
information indicates any. Note that many versions of gcc(1) cannot parse this option and will issue a warning. SUSv2 does not
include %'F.

(Reply to this) (Parent)


[info]nikonor
2009-11-11 07:22 am UTC (link)
perl -e '$a = 123456789.09; $a =~ s/(?<=\d)(?=(?:\d{3})+(?!\d))/ /g;print "!$a!\n"'

в одной книжке нашел. вроде такого варианта еще не было.

(Reply to this) (Thread)


[info]pavel_kudinov
2009-11-11 09:16 pm UTC (link)
красиво

(Reply to this) (Parent)


[info]xuntaka
2009-11-11 08:45 am UTC (link)
Сука задроты %)
Попрограммируйте Дозоры - отучитесь ;)

(Reply to this)


(30 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…