view release on metacpan or search on metacpan
lib/Aion/Format.pm view on Meta::CPAN
#show_refcount => 1,
#show_memsize => 1,
caller_info => 1,
output => 'stdout',
#unicode_charnames => 1,
};
#@category ÐовÑÑки
# ÐовÑÑка Ð´Ð»Ñ STDERR
sub trapperr(&) {
my $sub = shift;
local *STDERR;
open STDERR, '>:utf8', \my $f;
$sub->();
close STDERR;
$f
}
# ÐовÑÑка Ð´Ð»Ñ STDOUT
sub trappout(&) {
my $sub = shift;
local *STDOUT;
open STDOUT, '>:utf8', \my $f;
$sub->();
close STDOUT;
$f
}
#@category ЦвеÑ
# ÐолоÑизиÑÑÐµÑ ÑекÑÑ escape-поÑледоваÑелÑноÑÑÑми: coloring("#{BOLD RED}ya#{}100!#RESET"), а заÑем - заменÑÐµÑ ÑоÑÐ¼Ð°Ñ sprintf-ом
sub coloring(@) {
my $s = shift;
$s =~ s!#\{(?<x>[\w \t]*)\}|#(?<x>\w+)!
my $x = $+{x};
$x = "RESET" if $x ~~ [qw/r R/];
Term::ANSIColor::color($x)
!nge;
sprintf $s, @_
}
# ÐеÑаÑÐ°ÐµÑ Ð² STDOUT вÑвод coloring
sub printcolor(@) {
print coloring @_
}
# ÐеÑаÑÐ°ÐµÑ Ð² STDERR вÑвод coloring
sub warncolor(@) {
print STDERR coloring @_
}
# ÐÐ»Ñ ÐºÑона: ÐиÑÐµÑ Ð² STDOUT
sub accesslog(@) {
print "[", POSIX::strftime("%F %T", localtime), "] ", coloring @_;
}
# ÐÐ»Ñ ÐºÑона: ÐиÑÐµÑ Ð² STDIN
sub errorlog(@) {
print STDERR "[", POSIX::strftime("%F %T", localtime), "] ", coloring @_;
}
#@category ÐÑеобÑазованиÑ
# ÐÑÐ¾Ð²Ð¾Ð´Ð¸Ñ ÑооÑвеÑÑÑвиÑ
#
# matches "...", qr/.../ => sub {...}, ...
#
sub matches($@) {
my $s = shift;
my $i = 0;
my $re = join "\n| ", map { $i++ % 2 == 0? "(?<I$i> $_ )": () } @_;
my $arg = \@_;
my $fn = sub {
for my $k (keys %+) {
return $arg->[$k]->() if do { $k =~ /^I(\d+)\z/ and $k = $1 }
}
};
lib/Aion/Format.pm view on Meta::CPAN
а a и i п p Ñ c Ñ eh
б b й y Ñ r Ñ ch Ñ ju
в v к k Ñ s Ñ sh Ñ ja
г g л l Ñ t Ñ sch
д d м m Ñ u Ñ qh
е e н n Ñ f Ñ y
Ñ jo о o Ñ
kh Ñ q
ж zh
з z
/;
sub transliterate($) {
my ($s) = @_;
$s =~ s/[а-ÑÑ]/lc($&) eq $&? $TRANS{$&}: ucfirst $TRANS{lc $&}/gier;
}
# ТÑанÑлиÑеÑÑиÑÑÐµÑ ÑекÑÑ, оÑÑавлÑÑ ÑолÑко лаÑинÑкие бÑÐºÐ²Ñ Ð¸ ÑиÑе
sub trans($) {
my ($s) = @_;
$s = transliterate $s;
$s =~ s{[-\s_]+}{-}g;
$s =~ s![^a-z-]!!gi;
$s =~ s!^-*(.*?)-*\z!$1!;
lc $s
}
#@category СÑÑоки
# ÐÑеобÑазÑÐµÑ Ð² ÑÑÑÐ¾ÐºÑ perl
sub to_str(;$) {
my ($s) = @_ == 0? $_: @_;
$s =~ s/[\\']/\\$&/g;
$s =~ s/^(.*)\z/'$1'/s;
$s
}
# ÐÑеобÑазÑÐµÑ Ð¸Ð· ÑÑÑоки perl
sub from_str(;$) {
my ($s) = @_ == 0? $_: @_;
$s =~ s/^'(.*)'\z/$1/s;
$s =~ s/\\([\\'])/$1/g;
$s
}
# УпÑоÑÑннÑй ÑзÑк ÑегÑлÑÑок
sub nous($) {
my ($templates) = @_;
my $x = join "|", map {
matches $_,
# СÑезаем вÑе пÑÐ¾Ð±ÐµÐ»Ñ Ñ ÐºÐ¾Ð½Ñа:
qr!\s*$! => sub {},
# СÑезаем вÑе наÑалÑнÑе ÑÑÑоки:
qr!^([ \t]*\n)*! => sub {},
# С наÑала каждой ÑÑÑоки 4 пÑобела или 0-3 пÑобела и ÑабÑлÑÑиÑ:
qr!^( {4}| {0,3}\t)!m => sub {},
# ÐÑÐ¾Ð±ÐµÐ»Ñ Ð² конÑе ÑÑÑоки и пÑобелÑнÑе ÑÑÑоки заÑем заменÑем на \s*
lib/Aion/Format.pm view on Meta::CPAN
qr!\)\)! => sub { ")" },
qr!\|\|! => sub { "|" },
# ÐÑÑалÑное - ÑÑкейпим:
qr!.*?! => sub { quotemeta $& },
} @$templates;
qr/$x/xsmn
}
# ÑоÑмиÑÑÐµÑ ÑеловекоÑиÑабелÑнÑй инÑеÑвал
sub sinterval($) {
my ($interval) = @_;
if(0 == int $interval) {
return sprintf "%.6f mks", $interval*1000_000 if 0 == int($interval*1000_000);
return sprintf "%.7f ms", $interval*1000 if 0 == int($interval*1000);
return sprintf "%.8f s", $interval;
}
my $hours = int($interval / (60*60));
my $minutes = int(($interval - $hours*60*60) / 60);
lib/Aion/Format.pm view on Meta::CPAN
#@category ЦиÑÑÑ
# пеÑÐµÐ²Ð¾Ð´Ð¸Ñ Ð² ÑимÑкÑÑ ÑиÑÑÐµÐ¼Ñ ÑÑиÑлениÑ
# N - нолÑ
# ЧеÑез каждÑÑ 1000 ÑÑавиÑÑÑ Ð¿Ñобел (ÑазделиÑÐµÐ»Ñ ÑазÑÑдов)
our @RIM_CIF = (
[ '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' ],
[ '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC' ],
[ '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM' ]
);
sub rim($) {
my ($a) = @_;
use bigint; $a+=0;
my $s;
for ( ; $a != 0 ; $a = int( $a / 1000 ) ) {
my $v = $a % 1000;
if ( $v == 0 ) {
$s = "M $s";
}
else {
my $d;
lib/Aion/Format.pm view on Meta::CPAN
our $CIF = join "", "0".."9", "A".."Z", "a".."z", "_-", # 64 Ñимвола Ð´Ð»Ñ 64-ÑиÑной ÑиÑÑÐµÐ¼Ñ ÑÑиÑлениÑ
(map chr, ord "Ð" .. ord "Я"), "ÐÐÐÐÐÐÐÐÐÐÒÐÐÐÐ
",
(map chr, ord "а" .. ord "Ñ"), "ÑÑÑÑÑÑÑÑÑÑÒÑÑÑÑ",
"âââ¦â â¡â¬â°â¹âââââ¢âââ¢âºÂ¤Â¦Â§Â©Â«Â¬Â®°±µ¶·â»", do { no utf8; chr 0xa0 }, # небÑквеннÑе ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¸Ð· cp1251
"!\"#\$%&'()*+,./:;<=>?\@[\\]^`{|}~", # ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¿ÑнкÑÑаÑии ASCII
" ", # пÑобел
(map chr, 0 .. 0x1F, 0x7F), # ÑпÑавлÑÑÑие ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ ASCII
# Ñимвол 152 (0x98) в cp1251 оÑÑÑÑÑÑвÑеÑ.
;
# ÐеÑÐµÐ²Ð¾Ð´Ð¸Ñ Ð½Ð°ÑÑÑалÑное ÑиÑло в заданнÑÑ ÑиÑÑÐµÐ¼Ñ ÑÑиÑлениÑ
sub to_radix($;$) {
use bigint;
my ($n, $radix) = @_;
$radix //= 64;
die "to_radix: The number system $radix is too large. Use NS before " . (1 + length $CIF) if $radix > length $CIF;
$n+=0; $radix+=0;
my $x = "";
for(;;) {
my $cif_idx = $n % $radix;
my $cif = substr $CIF, $cif_idx, 1;
$x =~ s/^/$cif/;
last unless $n = int($n / $radix);
}
return $x;
}
# ÐаÑÑÐ¸Ñ Ð½Ð°ÑÑÑалÑное ÑиÑло в Ñказанной ÑиÑÑеме ÑÑиÑлениÑ
sub from_radix(@) {
use bigint;
my ($s, $radix) = @_;
$radix //= 64;
$radix+=0;
die "from_radix: The number system $radix is too large. Use NS before " . (1 + length $CIF) if $radix > length $CIF;
my $x = 0;
for my $ch (split "", $s) {
$x = $x*$radix + index $CIF, $ch;
}
return $x;
}
# ÐкÑÑглÑÐµÑ Ð´Ð¾ Ñказанного ÑазÑÑда ÑиÑла
sub round($;$) {
my ($x, $dec) = @_;
$dec //= 0;
my $prec = 10**$dec;
int($x*$prec + 0.5) / $prec
}
#@category ÐеÑÑ (measure)
# добавлÑÐµÑ ÑазделиÑели Ð¼ÐµÐ¶Ð´Ñ ÑазÑÑдами ÑиÑла
sub num($) {
my ($s) = @_;
my $sep = " "; # ÐеÑазÑÑвнÑй пÑобел
my $dec = ".";
($s, $sep, $dec) = @$s == 2? @$s: (@$s, $dec) if ref $s;
my ($x, $y) = split /\./, $s;
$y = "$dec$y" if defined $y;
$x = reverse $x;
$x =~ s!\d{3}!$&$sep!g;
$x =~ s!$sep([+-]?)$!$1!;
reverse($x) . $y;
}
# ÐобавлÑÐµÑ ÑазÑÑÐ´Ñ ÑиÑел и добавлÑÐµÑ ÐµÐ´Ð¸Ð½Ð¸ÑÑ Ð¸Ð·Ð¼ÐµÑениÑ
sub kb_size($) {
my ($n) = @_;
return num(round($n / 1024 / 1024 / 1024)) . "G" if $n >= 1024 * 1024 * 1024;
return num(round($n / 1024 / 1024)) . "M" if $n >= 1024 * 1024;
return num(round($n / 1024)) . "k" if $n >= 1024;
return num(round($n)) . "b";
}
# ÐÑÑавлÑÐµÑ $n ÑиÑÑ Ð´Ð¾ и поÑле ÑоÑки: 10.11 = 10, 0.00012 = 0.00012, 1.2345 = 1.2, еÑли $n = 2
sub sround($;$) {
my ($number, $digits) = @_;
$digits //= 2;
my $num = sprintf("%.100f", $number);
$num =~ /^-?0?(\d*)\.(0*)[1-9]/;
return "" . round($num, $digits + length $2) if length($1) == 0;
my $k = $digits - length $1;
return "" . round($num, $k < 0? 0: $k);
}
# ÐибибайÑ
sub KiB() { 2**10 }
# ÐебибайÑ
sub MiB() { 2**20 }
# ÐибибайÑ
sub GiB() { 2**30 }
# ТебибайÑ
sub TiB() { 2**40 }
# ÐакÑимÑм в даннÑÑ
TinyText ÐаÑии
sub xxS { 255 }
# ÐакÑимÑм в даннÑÑ
Text ÐаÑии
sub xxR { 64*KiB-1 }
# ÐакÑимÑм в даннÑÑ
MediumText ÐаÑии
sub xxM { 16*MiB-1 }
lib/Aion/Format.pm view on Meta::CPAN
70 => "Ð´Ð»Ñ 13 Ð»ÐµÑ (7-й клаÑÑ)",
60 => "Ð´Ð»Ñ 8-Ñ
и 9-Ñ
клаÑÑов",
50 => "Ð´Ð»Ñ 10-Ñ
, 12-Ñ
клаÑÑов",
40 => "Ð´Ð»Ñ ÑÑÑденÑов",
30 => "Ð´Ð»Ñ Ð±Ð°ÐºÐ°Ð»Ð°Ð²Ñов",
20 => "Ð´Ð»Ñ Ð¼Ð°Ð³Ð¸ÑÑÑов",
10 => "Ð´Ð»Ñ Ð¿ÑоÑеÑÑионалов",
0 => "Ð´Ð»Ñ Ð°ÐºÐ°Ð´ÐµÐ¼Ð¸ÐºÐ¾Ð²",
);
sub flesch_index_human($) {
my ($flesch_index) = @_;
$FLESCH_INDEX_NAMES{int($flesch_index / 10) * 10} // "неÑвÑзнÑй ÑÑÑÑкий ÑекÑÑ"
}
1;
__END__
=encoding utf-8
lib/Aion/Format/Html.pm view on Meta::CPAN
# â «пики» (каÑÑоÑÐ½Ð°Ñ Ð¼Ð°ÑÑÑ) ♠ ♠
spades => 9824,
# ⣠«ÑÑеÑÑ» (каÑÑоÑÐ½Ð°Ñ Ð¼Ð°ÑÑÑ) ♣ ♣
clubs => 9827,
# ⥠«ÑеÑвÑ» (каÑÑоÑÐ½Ð°Ñ Ð¼Ð°ÑÑÑ) ♥ ♥
hearts => 9829,
# ⦠«бÑбнÑ» (каÑÑоÑÐ½Ð°Ñ Ð¼Ð°ÑÑÑ) ♦ ♦
diams => 9830,
);
sub _set(@) { +{ map { $_ => 1 } @_ } }
# Теги не имеÑÑие закÑÑваÑÑего Ñега
our %SINGLE_TAG = %{ _set qw/area base br col embed hr img input link meta param source track wbr/ };
# <li> закÑÑваеÑÑÑ, еÑли пÑиÑ
Ð¾Ð´Ð¸Ñ </ol> или </ul>
our %TOP_CLOSE_TAG = (
li => _set(qw/ol ul/),
caption => _set(qw/table/),
thead => _set(qw/table/),
tbody => _set(qw/table/),
lib/Aion/Format/Html.pm view on Meta::CPAN
li => _set(qw/li/),
dt => _set(qw/dt dd/),
dd => _set(qw/dt dd/),
rt => _set(qw/rt rp/),
rp => _set(qw/rt rp/),
option => _set(qw/option optgroup/),
optgroup => _set(qw/optgroup/),
);
# ÐÑовеÑÑеÑ, ÑÑо Ñег â одиноÑнÑй
sub is_single_tag(;$) {
exists $SINGLE_TAG{$_[0] // $_}
}
# ÐабÑаÑÑÐ²Ð°ÐµÑ Ñег в ÑÑек и возвÑаÑÐ°ÐµÑ Ð·Ð°ÐºÑÑÑÑе
sub in_tag(\@$$) {
my ($S, $tag, $atag) = @_;
# ÐÑбÑаÑÑваем из ÑÑека пÑедÑдÑÑий Ñег
my @ret;
push @ret, pop @$S while @$S and
($TOP_NEW_TAG{ $S->[$#$S][0] })->{$tag};
push @$S, [$tag, $atag] unless exists $SINGLE_TAG{$tag};
@ret
}
# ÐÑбÑаÑÑÐ²Ð°ÐµÑ Ñег из ÑÑека. ÐозвÑаÑÐ°ÐµÑ Ð²ÑдавленнÑе им и вÑбÑаÑÑÐ²Ð°ÐµÑ Ð¸ÑклÑÑение, еÑли Ñакого в ÑÑеке неÑ
sub out_tag(\@$) {
my ($S, $tag) = @_;
# ÐÑо одиноÑнÑй Ñег - он не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð·Ð°ÐºÑÑваÑÑим
die "</$tag> is a single tag - it cannot be a closing tag" if exists $SINGLE_TAG{$tag};
# закÑÑваем пÑедÑдÑÑий, еÑли нÑжно
my @ret;
push @ret, pop @$S while @$S and
($TOP_CLOSE_TAG{$S->[$#$S][0]})->{$tag};
lib/Aion/Format/Html.pm view on Meta::CPAN
push @ret, pop @$S;
@ret
}
=pod
Ð Ð°Ð·Ð±Ð¸Ð²Ð°ÐµÑ ÑекÑÑ Ð½Ð° ÑÑÑаниÑÑ Ñ ÑÑÑÑом html-Ñегов
1. html-Ñег должен бÑÑÑ Ñак же ÑазнеÑÑн на ÑÑÑаниÑÑ.
=cut
sub split_on_pages(@) {
my ($html, $symbols_on_page, $by) = @_;
# Ðа какое ÑаÑÑÑоÑние ÑÑÑаниÑа Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе
$by //= $symbols_on_page / 3 < 1000 ? int($symbols_on_page / 3): 1000;
my $max = $symbols_on_page + $by;
my @pages; # маÑÑив ÑÑÑаниÑ
my @page; # маÑÑив ÑлеменÑов ÑекÑÑа и Ñегов ÑекÑÑей ÑÑÑаниÑÑ
my $c = 0; # колиÑеÑÑво Ñимволов в ÑекÑÑей ÑÑÑаниÑе
my $i_page = 0; # Ð¸Ð½Ð´ÐµÐºÑ ÑлеменÑа @page коÑоÑÑй пÑивÑÑил ÑÐ°Ð·Ð¼ÐµÑ ÑÑÑаниÑÑ
lib/Aion/Format/Html.pm view on Meta::CPAN
align border hspace vspace longdesc axis char charoff summary
colspan rowspan
border cite bgcolor color
coords
/;
# ÑÑÐµÐ·Ð°ÐµÑ Ñ html-Ñ Ð¾Ð¿Ð°ÑнÑе, а Ñак же неведомÑе Ñеги
sub safe_html($;$) {
(local $_, my $link) = @_;
my $f = sub {
return "" if !exists $SAFE_TAG{lc $2};
return "</$2>" if $1 ne "";
my $tag = $2;
my $x = $3;
my @attrs;
while($x =~ /
\b (?<attr> [a-z][a-z\d]*) ( \s*=\s* ( (?<quot> ") (?<val> [^"]*)" | (?<quot> ') (?<val> [^']*)' | (?<val> \S*) ) )?
lib/Aion/Format/Json.pm view on Meta::CPAN
our @EXPORT = our @EXPORT_OK = grep {
*{$Aion::Format::Json::{$_}}{CODE} && !/^(_|(NaN|import)\z)/n
} keys %Aion::Format::Json::;
#@category json
# ÐаÑÑÑаиваем json
our $JSON = JSON::XS->new->allow_nonref->indent(1)->space_after(1)->canonical(1);
# Ð json
sub to_json(;$) {
$JSON->encode(@_ == 0? $_: @_)
}
# Ðз json
sub from_json(;$) {
$JSON->decode(@_ == 0? $_: @_)
}
1;
__END__
=encoding utf-8
=head1 NAME
lib/Aion/Format/Url.pm view on Meta::CPAN
our @EXPORT = our @EXPORT_OK = grep {
ref \$Aion::Format::Url::{$_} eq "GLOB"
&& *{$Aion::Format::Url::{$_}}{CODE} && !/^(_|(NaN|import)\z)/n
} keys %Aion::Format::Url::;
#@category escape url
use constant UNSAFE_RFC3986 => qr/[^A-Za-z0-9\-\._~]/;
sub to_url_param(;$) {
my ($param) = @_ == 0? $_: @_;
$param =~ s/${\ UNSAFE_RFC3986}/$& eq " "? "+": sprintf "%%%02X", ord $&/age;
$param
}
sub _escape_url_params {
my ($key, $param) = @_;
!defined($param)? ():
$param eq 1? $key:
ref $param eq "HASH"? do {
join "&", map _escape_url_params("${key}[$_]", $param->{$_}), sort keys %$param
}:
ref $param eq "ARRAY"? do {
join "&", map _escape_url_params("${key}[]", $_), @$param
}:
join "", $key, "=", to_url_param $param
}
sub to_url_params(;$) {
my ($param) = @_ == 0? $_: @_;
if(ref $param eq "HASH") {
join "&", map _escape_url_params($_, $param->{$_}), sort keys %$param
}
else {
join "&", List::Util::pairmap { _escape_url_params($a, $b) } @$param
}
}
lib/Aion/Format/Url.pm view on Meta::CPAN
( \# (?<hash> .* ) )?
\z!xn;
return %+;
}
# 1 - set / in each page, if it not file (*.*), or 0 - unset
use config DIR => 0;
use config ONPAGE => "off://off";
# ÐаÑÑÐ¸Ñ Ð¸ ноÑмализÑÐµÑ url
sub parse_url($;$$) {
my ($link, $onpage, $dir) = @_;
$onpage //= ONPAGE;
$dir //= DIR;
my $orig = $link;
my %link = _parse_url $link;
my %onpage = _parse_url $onpage;
if(!exists $link{path}) {
$link{path} = join "", $onpage{path}, $onpage{path} =~ m!/\z!? (): "/", $link{part};
lib/Aion/Format/Url.pm view on Meta::CPAN
$link{dom},
$link{path},
length($link{query})? ("?", $link{query}): (),
length($link{hash})? ("#", $link{hash}): (),
;
return \%link;
}
# ÐоÑмализÑÐµÑ url
sub normalize_url($;$$) {
parse_url($_[0], $_[1], $_[2])->{link}
}
1;
__END__
=encoding utf-8
=head1 NAME