package HTML::Fraction;
use strict;
use warnings;
our $VERSION = "0.50";
# numbers with an exact fractional part
my %dec = (
'25' => "1/4",
'5' => "1/2",
'75' => "3/4",
'2' => "1/5",
'4' => "2/5",
'6' => "3/5",
'8' => "4/5",
'125' => "1/8",
'375' => "3/8",
'625' => "5/8",
'875' => "7/8",
'1' => "1/10",
);
# two decimal
my %tdp = (
'13' => "1/8",
'38' => "3/8",
'63' => "5/8",
'88' => "7/8",
);
my %name2char = (
'1/4' => '¼',
'1/2' => '½',
'3/4' => '¾',
'0/3' => '↉',
'1/3' => '⅓',
'2/3' => '⅔',
'1/5' => '⅕',
'2/5' => '⅖',
'3/5' => '⅗',
'4/5' => '⅘',
'1/6' => '⅙',
'5/6' => '⅚',
'1/7' => '⅐',
'1/8' => '⅛',
'3/8' => '⅜',
'5/8' => '⅝',
'7/8' => '⅞',
'1/9' => '⅑',
'1/10' => '⅒',
);
sub _name2char { shift; $name2char{shift()} }
sub new { bless {}, shift }
sub tweak
{
my ($self, $in) = @_;
return $self->tweak_frac($self->tweak_dec($in));
}
sub tweak_frac
{
my ($self, $in) = @_;
my $thingy = join '|', keys %name2char;
$in =~ s{\b($thingy)\b}{
$self->_name2char($1)
}ge;
# repeatin
return $in;
}
sub tweak_dec
{
my ($self, $in) = @_;
my $thingy = join '|', keys %dec;
$in =~ s{([0-9]*)\.($thingy)0*\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char($dec{$2})
}ge;
$thingy = join '|', keys %tdp;
$in =~ s{([0-9]*)\.($thingy)\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char($tdp{$2})
}ge;
$in =~ s{([0-9]*)\.33+\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("1/3")
}ge;
$in =~ s{([0-9]*)\.66*7+\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("2/3")
}ge;
$in =~ s{([0-9]*)\.83+\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("5/6")
}ge;
$in =~ s{([0-9]*)\.16*7+\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("1/6")
}ge;
$in =~ s{([0-9]*)\.11+\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("1/9")
}ge;
# 0.142857142857143
$in =~ s{
([0-9]*)
\.
14
(?:
3|2(?:
9|8(?:
6|5(?:
7(?: 1(?:4\d*)? )?
)
)
)
)?
\b}{
no warnings;
($1+0 ? $1 : "") . $self->_name2char("1/7")
}gex;
return $in;
}
1;
__END__
=head1 NAME
HTML::Fraction - Encode fractions as HTML entities
=head1 SYNOPSIS
my $fraction = HTML::Fraction->new;
print $fraction->tweak($html);
=head1 DESCRIPTION
The L<HTML::Fraction> encodes fractions as HTML entities. Some very
common fractions have HTML entities (eg C<1/2> is C<½>;). Additionally,
common vulgar fractions have Unicode characters (eg C<1/5> is C<⅕>). This
module takes a string and encodes fractions as entities: this means that
it will look pretty in the browser.
Fractions that are supported:
1/4, 1/2, 3/4, 0/3, 1/3, 2/3, 1/5, 2/5, 3/5,
4/5, 1/6, 5/6, 1/7, 1/8, 3/8, 5/8, 7/8, 1/9, 1/10
Fractions may be in the string in the form numerator slash denominator (C<1/5>)
or in decimal form (C<0.5>). Numbers must be equal to the fraction to two
decimal places. This module supports converting whole and fractional decimal
numbers (e.g. C<2.25>.)
For sanity the decimal C<0> will not be turned into the unicode for C<0/3>
=head1 CONSTRUCTOR
=head2 new
The constructor takes no arguments:
my $fraction = HTML::Fraction->new;
=head1 METHODS
=head2 tweak
Encode the fractions in the HTML as HTML entities:
print $fraction->tweak($html);
=head2 tweak_frac
Encode the fractions that are in the form "1/3" or "5/6" in the HTML as HTML
entities, but not decimal fractions of the form "0.5".
=head2 tweak_dec
Encode the fractions that are in the form "0.5" or "0.5" in the HTML as HTML
entities, but not fractions of the form "1/2" or "1/3".
=head1 AUTHOR
Leon Brocard, C<< <acme@astray.com> >>. Mark Fowler C<< <mark@twoshortplanks> >>
added some code, and probably some bugs.
=head1 COPYRIGHT
Copyright (C) 2005, 2012 Leon Brocard
This module is free software; you can redistribute it or modify it
under the same terms as Perl itself.
=head1 BUGS
We don't perform normalisation of the denominator and numerator so "4/6" is
not converted like C<2/3> is. This is intentional.
C<2.25> doesn't render to the same thing as C<2 1/2> (the latter has a space
between the digit 2 and the fraction.)
C<1/7> doesn't represent as a reoccuring pattern of digits in decimal therefore
we don't check that digits after C<0.14285714> are correct, and assume that
they are.