File Coverage

blib/lib/Unicode/Decompose.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Unicode::Decompose;
2              
3 1     1   6903 use lib "../../../lib";
  1         1129  
  1         7  
4 1     1   201 use 5.006;
  1         6  
  1         40  
5 1     1   6 use strict;
  1         3  
  1         33  
6 1     1   6 use warnings;
  1         2  
  1         34  
7 1     1   1334 use utf8;
  1         8  
  1         4  
8 1     1   1606 use UnicodeCD qw(charinfo compexcl);
  0            
  0            
9              
10             require Exporter;
11             require DynaLoader;
12              
13             our @ISA = qw(Exporter DynaLoader);
14              
15             our %EXPORT_TAGS = ( 'all' => [ qw(
16             normalize normalize_d order decompose recompose
17             ) ] );
18              
19             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
20              
21             our @EXPORT = qw();
22             our $VERSION = '0.02';
23              
24             our %compat;
25             our %canon;
26              
27             # First, load up the decomposition table
28             my @decomp = split /\n/, require "unicode/Decomposition.pl" or die $@;
29             my %decomp;
30             while ($_=pop @decomp) {
31             chomp;
32             my ($char,@line) = split;
33             $decomp{$char} = [
34             map { exists $decomp{$_} ? @{$decomp{$_}} : $_ } @line
35             ];
36             }
37              
38             # Then remove the recursion from it
39             my $changed;
40             do {
41             $changed = 0;
42             while (my($k,$v) = each %decomp) {
43             $decomp{$k} = [ map { exists $decomp{$_} ? do { $changed++; @{$decomp{$_}} } : $_ } @$v ];
44             }
45             } while $changed;
46              
47             # Now split it into canon and compat
48             while (my($k,$v) = each %decomp) {
49             $compat{pack("U*", hex $k)} = pack "U*", map { hex $_} grep !/
50             next if "@$v" =~ /
51             $canon{pack("U*", hex $k)} = pack "U*", map { hex $_} @$v;
52             }
53              
54             my @ok_keys;
55             # Recomposition
56             for (keys %canon) {
57             my $x = $_;
58             next if (compexcl ord $x); # compexcl eats $_, bluh.
59             push @ok_keys, $x;
60             }
61              
62             my %recomp = map { $canon{$_} => $_ } @ok_keys;
63             my $recomppat = join "|", reverse sort keys %recomp;
64              
65             bootstrap Unicode::Decompose $VERSION;
66              
67             sub normalize {
68             my $a = shift;
69             _decompose($a, "canon");
70             return recompose(order($a));
71             }
72             sub normalize_d {
73             my $a = shift;
74             _decompose($a, "canon");
75             return order($a);
76             }
77              
78             sub decompose {
79             my $a = shift;
80             decompose($a, "canon");
81             return $a;
82             }
83              
84             sub order {
85             my $str = shift;
86             my @chars = ($str =~ /(\X)*/);
87             my $result;
88             for (@chars) {
89             # my ($head, @others) = /^(\PM)(\pM)*$/; Doesn't work, damn!
90             s/^(\PM)// or die ;
91             my $head = $1;
92             my @others;
93             push @others, $1 while s/^(\pM)//;
94             $result .= $head;
95             next unless @others;
96             $result .= join '', sort { charinfo(ord $a)->{combining} <=> charinfo(ord($b))->{combining} } @others;
97             }
98             return $result;
99             }
100              
101             sub recompose {
102             my $a = shift;
103             $a =~ s/($recomppat)/$recomp{$1}/g;
104             return $a;
105             }
106              
107             1;
108             __END__