| Lingua-JA-Number documentation | Contained in the Lingua-JA-Number distribution. |
Lingua::JA::Number - Translate Numbers into Japanese
use Lingua::JA::Number;
my @words = Lingua::JA::Number::to_string(1234);
print join('-', @words), "\n";
# "sen-ni-hyaku-san-ju-yon"
Lingua::JA::Number translates numbers into Japanese.
Its to_string function takes a integer number
and transforms it to the equivalent cardinal
number romaji string. This'll show exactly how
the number is pronounced in Japanese.
Here's how the Japanese cardinal numbering scheme works: The numbers 1..10 translate to ichi, ni, san, yon, go, roku, nana, hachi, kyu. 10 is yu, 100 is hyaku, 1000 is sen and 10000 is man.
Similar to English, multi-digit numbers are put together using decimal weights: 15 is 10 + 5, 723 is 7*100 + 2*10 + 3 and 6973 is 6*1000 + 9*100 + 7*10 + 3. Therefore, 15 is pronounced yu-go, 123 is hyaku-ni-yu-san and 6973 is roku-san-kyu-hyaku-nana-san.
Like in all natural languages, there's a couple of exceptions: 300 isn't san-hyaku but san-byaku, 600 isn't roku-hyaku but ro-p-pyaku and 800 isn't hachi-hyaku but ha-p-pyaku. Also, in the thousands, 3000 is san-zen and 8000 is ha-s-sen. Also, there's more exceptions for numbers of 1,000,000,000,000 and greater.
And, numbers aren't split into groups of 3 (like in 1,000,000) but in groups of 4, like in 100,0000, which is pronounced hyaku-man (100 times 10000).
Here's a quick script jn which will quiz
you with random numbers (or romaji strings
if invoked as jn -r) and reveal the solution
after you hit the Enter key. It requires
Term::ReadKey, which is available from CPAN:
#!/usr/bin/perl
use warnings;
use strict;
use Term::ReadKey;
use Getopt::Std;
use Lingua::JA::Number qw(to_string);
getopts('r', \ my %opts);
my @length = (2, 3, 4); # Prompt for 2-,3-
# and 4-digit numbers
$| = 1;
while(1) {
my $digits = $length[rand(@length)];
my $ques = int rand(10**$digits);
next unless $ques;
my $ans = join '-', to_string($ques);
if($opts{r}) {
($ans, $ques) = ($ques, $ans);
}
print "$ques ... ";
ReadMode("noecho");
ReadLine(0);
ReadMode("normal");
print $ans, "\n";
}
I've just taken a beginner's Japanese class, so bear with me. Bug reports are most welcome.
Also, I'm planning on providing additional modules
Lingua::JA::Number::Tall,
Lingua::JA::Number::Flat,
Lingua::JA::Number::Person,
Lingua::JA::Number::Misc to cover the
idiosyncrasies of japanese counting of tall and
flat things, persons and miscellaneous items.
Mike Schilli <m@perlmeister.com>
Copyright (c) 2001 Mike Schilli. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Lingua-JA-Number documentation | Contained in the Lingua-JA-Number distribution. |
################################################## # Lingua::JA::Number # # Mike Schilli, 2001 (m@perlmeister.com) ################################################## package Lingua::JA::Number; use warnings; use strict; use Exporter (); our $VERSION = 0.01; our @ISA = qw (Exporter); our @EXPORT = qw (); our @EXPORT_OK = qw ( to_string ); our %EXPORT_TAGS = (); my %N2J = qw( 1 ichi 2 ni 3 san 4 yon 5 go 6 roku 7 nana 8 hachi 9 kyu 10 ju 100 hyaku 1000 sen); my %N2J_EXCP = qw( 300 san-byaku 600 ro-p-pyaku 800 ha-p-pyaku 3000 san-zen 8000 ha-s-sen); my @N2J_BLOCK = ("", "man", "oku", "cho"); my %N2J_BLOCK_EXCP = qw( 1 i-t-cho 8 ha-t-cho 0 ju-t-cho); ################################################## sub to_string { ################################################## my $n = shift; if($n < 1 || $n >= 1E16) { warn "$n needs to be >=1 and <1E16.\n"; return undef; } my @result = (); $n = reverse $n; my $bix = 0; while($n =~ /(\d{1,4})/g) { my $b = scalar reverse($1); my @r = blockof4_to_string($b); if($bix && @r) { if($bix == 3 && $b =~ /[1-9]0$|[18]$/) { $r[$#r] = $N2J_BLOCK_EXCP{$b%10}; } else { push @r, $N2J_BLOCK[$bix]; } } unshift @result, @r; $bix++; } return @result; } ################################################## sub blockof4_to_string { ################################################## my $n = shift; return undef if $n > 9999 or $n < 0; return "" unless $n; my @result = (); my @digits = split //, sprintf("%04d", $n); my @weights = (1000, 100, 10, 1); for my $i (0..3) { next unless $digits[$i]; my $v = $digits[$i] * $weights[$i]; push @result, $N2J_EXCP{$v} || $N2J{$v} || ($N2J{$digits[$i]}, $N2J{$weights[$i]}); } return @result; } 1; __END__