This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add a regression test for bug #32193, and make the
[perl5.git] / lib / Unicode / Collate.pm
1 package Unicode::Collate;
2
3 BEGIN {
4     unless ("A" eq pack('U', 0x41)) {
5         die "Unicode::Collate cannot stringify a Unicode code point\n";
6     }
7 }
8
9 use 5.006;
10 use strict;
11 use warnings;
12 use Carp;
13 use File::Spec;
14
15 no warnings 'utf8';
16
17 our $VERSION = '0.40';
18 our $PACKAGE = __PACKAGE__;
19
20 my @Path = qw(Unicode Collate);
21 my $KeyFile = "allkeys.txt";
22
23 # Perl's boolean
24 use constant TRUE  => 1;
25 use constant FALSE => "";
26 use constant NOMATCHPOS => -1;
27
28 # A coderef to get combining class imported from Unicode::Normalize
29 # (i.e. \&Unicode::Normalize::getCombinClass).
30 # This is also used as a HAS_UNICODE_NORMALIZE flag.
31 my $CVgetCombinClass;
32
33 # Supported Levels
34 use constant MinLevel => 1;
35 use constant MaxLevel => 4;
36
37 # Minimum weights at level 2 and 3, respectively
38 use constant Min2Wt => 0x20;
39 use constant Min3Wt => 0x02;
40
41 # Shifted weight at 4th level
42 use constant Shift4Wt => 0xFFFF;
43
44 # A boolean for Variable and 16-bit weights at 4 levels of Collation Element
45 # PROBLEM: The Default Unicode Collation Element Table
46 # has weights over 0xFFFF at the 4th level.
47 # The tie-breaking in the variable weights
48 # other than "shift" (as well as "shift-trimmed") is unreliable.
49 use constant VCE_TEMPLATE => 'Cn4';
50
51 # A sort key: 16-bit weights
52 # See also the PROBLEM on VCE_TEMPLATE above.
53 use constant KEY_TEMPLATE => 'n*';
54
55 # Level separator in a sort key:
56 # i.e. pack(KEY_TEMPLATE, 0)
57 use constant LEVEL_SEP => "\0\0";
58
59 # As Unicode code point separator for hash keys.
60 # A joined code point string (denoted by JCPS below)
61 # like "65;768" is used for internal processing
62 # instead of Perl's Unicode string like "\x41\x{300}",
63 # as the native code point is different from the Unicode code point
64 # on EBCDIC platform.
65 # This character must not be included in any stringified
66 # representation of an integer.
67 use constant CODE_SEP => ';';
68
69 # boolean values of variable weights
70 use constant NON_VAR => 0; # Non-Variable character
71 use constant VAR     => 1; # Variable character
72
73 # specific code points
74 use constant Hangul_LBase  => 0x1100;
75 use constant Hangul_LIni   => 0x1100;
76 use constant Hangul_LFin   => 0x1159;
77 use constant Hangul_LFill  => 0x115F;
78 use constant Hangul_VBase  => 0x1161;
79 use constant Hangul_VIni   => 0x1160;
80 use constant Hangul_VFin   => 0x11A2;
81 use constant Hangul_TBase  => 0x11A7;
82 use constant Hangul_TIni   => 0x11A8;
83 use constant Hangul_TFin   => 0x11F9;
84 use constant Hangul_TCount => 28;
85 use constant Hangul_NCount => 588;
86 use constant Hangul_SBase  => 0xAC00;
87 use constant Hangul_SIni   => 0xAC00;
88 use constant Hangul_SFin   => 0xD7A3;
89 use constant CJK_UidIni    => 0x4E00;
90 use constant CJK_UidFin    => 0x9FA5;
91 use constant CJK_ExtAIni   => 0x3400;
92 use constant CJK_ExtAFin   => 0x4DB5;
93 use constant CJK_ExtBIni   => 0x20000;
94 use constant CJK_ExtBFin   => 0x2A6D6;
95 use constant BMP_Max       => 0xFFFF;
96
97 # Logical_Order_Exception in PropList.txt
98 # TODO: synchronization with change of PropList.txt.
99 my $DefaultRearrange = [ 0x0E40..0x0E44, 0x0EC0..0x0EC4 ];
100
101 sub UCA_Version { "11" }
102
103 sub Base_Unicode_Version { "4.0" }
104
105 ######
106
107 sub pack_U {
108     return pack('U*', @_);
109 }
110
111 sub unpack_U {
112     return unpack('U*', pack('U*').shift);
113 }
114
115 ######
116
117 my (%VariableOK);
118 @VariableOK{ qw/
119     blanked  non-ignorable  shifted  shift-trimmed
120   / } = (); # keys lowercased
121
122 our @ChangeOK = qw/
123     alternate backwards level normalization rearrange
124     katakana_before_hiragana upper_before_lower
125     overrideHangul overrideCJK preprocess UCA_Version
126     hangul_terminator variable
127   /;
128
129 our @ChangeNG = qw/
130     entry mapping table maxlength
131     ignoreChar ignoreName undefChar undefName variableTable
132     versionTable alternateTable backwardsTable forwardsTable rearrangeTable
133     derivCode normCode rearrangeHash
134     backwardsFlag
135   /;
136 # The hash key 'ignored' is deleted at v 0.21.
137 # The hash key 'isShift' is deleted at v 0.23.
138 # The hash key 'combining' is deleted at v 0.24.
139 # The hash key 'entries' is deleted at v 0.30.
140 # The hash key 'L3_ignorable' is deleted at v 0.40.
141
142 sub version {
143     my $self = shift;
144     return $self->{versionTable} || 'unknown';
145 }
146
147 my (%ChangeOK, %ChangeNG);
148 @ChangeOK{ @ChangeOK } = ();
149 @ChangeNG{ @ChangeNG } = ();
150
151 sub change {
152     my $self = shift;
153     my %hash = @_;
154     my %old;
155     if (exists $hash{variable} && exists $hash{alternate}) {
156         delete $hash{alternate};
157     }
158     elsif (!exists $hash{variable} && exists $hash{alternate}) {
159         $hash{variable} = $hash{alternate};
160     }
161     foreach my $k (keys %hash) {
162         if (exists $ChangeOK{$k}) {
163             $old{$k} = $self->{$k};
164             $self->{$k} = $hash{$k};
165         }
166         elsif (exists $ChangeNG{$k}) {
167             croak "change of $k via change() is not allowed!";
168         }
169         # else => ignored
170     }
171     $self->checkCollator;
172     return wantarray ? %old : $self;
173 }
174
175 sub _checkLevel {
176     my $level = shift;
177     my $key   = shift; # 'level' or 'backwards'
178     MinLevel <= $level or croak sprintf
179         "Illegal level %d (in value for key '%s') lower than %d.",
180             $level, $key, MinLevel;
181     $level <= MaxLevel or croak sprintf
182         "Unsupported level %d (in value for key '%s') higher than %d.",
183             $level, $key, MaxLevel;
184 }
185
186 my %DerivCode = (
187     8 => \&_derivCE_8,
188     9 => \&_derivCE_9,
189    11 => \&_derivCE_9, # 11 == 9
190 );
191
192 sub checkCollator {
193     my $self = shift;
194     _checkLevel($self->{level}, "level");
195
196     $self->{derivCode} = $DerivCode{ $self->{UCA_Version} }
197         or croak "Illegal UCA version (passed $self->{UCA_Version}).";
198
199     $self->{variable} ||= $self->{alternate} || $self->{variableTable} ||
200                                 $self->{alternateTable} || 'shifted';
201     $self->{variable} = $self->{alternate} = lc($self->{variable});
202     exists $VariableOK{ $self->{variable} }
203         or croak "$PACKAGE unknown variable tag name: $self->{variable}";
204
205     if (! defined $self->{backwards}) {
206         $self->{backwardsFlag} = 0;
207     }
208     elsif (! ref $self->{backwards}) {
209         _checkLevel($self->{backwards}, "backwards");
210         $self->{backwardsFlag} = 1 << $self->{backwards};
211     }
212     else {
213         my %level;
214         $self->{backwardsFlag} = 0;
215         for my $b (@{ $self->{backwards} }) {
216             _checkLevel($b, "backwards");
217             $level{$b} = 1;
218         }
219         for my $v (sort keys %level) {
220             $self->{backwardsFlag} += 1 << $v;
221         }
222     }
223
224     defined $self->{rearrange} or $self->{rearrange} = [];
225     ref $self->{rearrange}
226         or croak "$PACKAGE: list for rearrangement must be store in ARRAYREF";
227
228     # keys of $self->{rearrangeHash} are $self->{rearrange}.
229     $self->{rearrangeHash} = undef;
230
231     if (@{ $self->{rearrange} }) {
232         @{ $self->{rearrangeHash} }{ @{ $self->{rearrange} } } = ();
233     }
234
235     $self->{normCode} = undef;
236
237     if (defined $self->{normalization}) {
238         eval { require Unicode::Normalize };
239         $@ and croak "Unicode::Normalize is required to normalize strings";
240
241         $CVgetCombinClass ||= \&Unicode::Normalize::getCombinClass;
242
243         if ($self->{normalization} =~ /^(?:NF)D\z/) { # tweak for default
244             $self->{normCode} = \&Unicode::Normalize::NFD;
245         }
246         elsif ($self->{normalization} ne 'prenormalized') {
247             my $norm = $self->{normalization};
248             $self->{normCode} = sub {
249                 Unicode::Normalize::normalize($norm, shift);
250             };
251             eval { $self->{normCode}->("") }; # try
252             $@ and croak "$PACKAGE unknown normalization form name: $norm";
253         }
254     }
255     return;
256 }
257
258 sub new
259 {
260     my $class = shift;
261     my $self = bless { @_ }, $class;
262
263     # If undef is passed explicitly, no file is read.
264     $self->{table} = $KeyFile if ! exists $self->{table};
265     $self->read_table if defined $self->{table};
266
267     if ($self->{entry}) {
268         while ($self->{entry} =~ /([^\n]+)/g) {
269             $self->parseEntry($1);
270         }
271     }
272
273     $self->{level} ||= MaxLevel;
274     $self->{UCA_Version} ||= UCA_Version();
275
276     $self->{overrideHangul} = FALSE
277         if ! exists $self->{overrideHangul};
278     $self->{overrideCJK} = FALSE
279         if ! exists $self->{overrideCJK};
280     $self->{normalization} = 'NFD'
281         if ! exists $self->{normalization};
282     $self->{rearrange} = $self->{rearrangeTable} || $DefaultRearrange
283         if ! exists $self->{rearrange};
284     $self->{backwards} = $self->{backwardsTable}
285         if ! exists $self->{backwards};
286
287     $self->checkCollator;
288
289     return $self;
290 }
291
292 sub read_table {
293     my $self = shift;
294
295     my($f, $fh);
296     foreach my $d (@INC) {
297         $f = File::Spec->catfile($d, @Path, $self->{table});
298         last if open($fh, $f);
299         $f = undef;
300     }
301     defined $f
302         or croak "$PACKAGE: $self->{table} is not found in @INC";
303
304     while (<$fh>) {
305         next if /^\s*#/;
306         unless (s/^\s*\@//) {
307             $self->parseEntry($_);
308             next;
309         }
310
311         if (/^version\s*(\S*)/) {
312             $self->{versionTable} ||= $1;
313         }
314         elsif (/^variable\s+(\S*)/) { # since UTS #10-9
315             $self->{variableTable} ||= $1;
316         }
317         elsif (/^alternate\s+(\S*)/) { # till UTS #10-8
318             $self->{alternateTable} ||= $1;
319         }
320         elsif (/^backwards\s+(\S*)/) {
321             push @{ $self->{backwardsTable} }, $1;
322         }
323         elsif (/^forwards\s+(\S*)/) { # parhaps no use
324             push @{ $self->{forwardsTable} }, $1;
325         }
326         elsif (/^rearrange\s+(.*)/) { # (\S*) is NG
327             push @{ $self->{rearrangeTable} }, _getHexArray($1);
328         }
329     }
330     close $fh;
331 }
332
333
334 ##
335 ## get $line, parse it, and write an entry in $self
336 ##
337 sub parseEntry
338 {
339     my $self = shift;
340     my $line = shift;
341     my($name, $entry, @uv, @key);
342
343     return if $line !~ /^\s*[0-9A-Fa-f]/;
344
345     # removes comment and gets name
346     $name = $1
347         if $line =~ s/[#%]\s*(.*)//;
348     return if defined $self->{undefName} && $name =~ /$self->{undefName}/;
349
350     # gets element
351     my($e, $k) = split /;/, $line;
352     croak "Wrong Entry: <charList> must be separated by ';' from <collElement>"
353         if ! $k;
354
355     @uv = _getHexArray($e);
356     return if !@uv;
357
358     $entry = join(CODE_SEP, @uv); # in JCPS
359
360     if (defined $self->{undefChar} || defined $self->{ignoreChar}) {
361         my $ele = pack_U(@uv);
362
363         # regarded as if it were not entried in the table
364         return
365             if defined $self->{undefChar} && $ele =~ /$self->{undefChar}/;
366
367         # replaced as completely ignorable
368         $k = '[.0000.0000.0000.0000]'
369             if defined $self->{ignoreChar} && $ele =~ /$self->{ignoreChar}/;
370     }
371
372     # replaced as completely ignorable
373     $k = '[.0000.0000.0000.0000]'
374         if defined $self->{ignoreName} && $name =~ /$self->{ignoreName}/;
375
376     my $is_L3_ignorable = TRUE;
377
378     foreach my $arr ($k =~ /\[([^\[\]]+)\]/g) { # SPACEs allowed
379         my $var = $arr =~ /\*/; # exactly /^\*/ but be lenient.
380         my @wt = _getHexArray($arr);
381         push @key, pack(VCE_TEMPLATE, $var, @wt);
382         $is_L3_ignorable = FALSE
383             if $wt[0] + $wt[1] + $wt[2] != 0;
384           # if $arr !~ /[1-9A-Fa-f]/; NG
385           # Conformance Test shows L3-ignorable is completely ignorable.
386         # For expansion, an entry $is_L3_ignorable
387         # if and only if "all" CEs are [.0000.0000.0000].
388     }
389
390     $self->{mapping}{$entry} = $is_L3_ignorable ? [] : \@key;
391
392     if (@uv > 1) {
393         (!$self->{maxlength}{$uv[0]} || $self->{maxlength}{$uv[0]} < @uv)
394             and $self->{maxlength}{$uv[0]} = @uv;
395     }
396 }
397
398
399 ##
400 ## VCE = _varCE(variable term, VCE)
401 ##
402 sub _varCE
403 {
404     my $vbl = shift;
405     my $vce = shift;
406     if ($vbl eq 'non-ignorable') {
407         return $vce;
408     }
409     my ($var, @wt) = unpack VCE_TEMPLATE, $vce;
410
411     if ($var) {
412         return pack(VCE_TEMPLATE, $var, 0, 0, 0,
413                 $vbl eq 'blanked' ? $wt[3] : $wt[0]);
414     }
415     elsif ($vbl eq 'blanked') {
416         return $vce;
417     }
418     else {
419         return pack(VCE_TEMPLATE, $var, @wt[0..2],
420             $vbl eq 'shifted' && $wt[0]+$wt[1]+$wt[2] ? Shift4Wt : 0);
421     }
422 }
423
424 sub viewSortKey
425 {
426     my $self = shift;
427     $self->visualizeSortKey($self->getSortKey(@_));
428 }
429
430 sub visualizeSortKey
431 {
432     my $self = shift;
433     my $view = join " ", map sprintf("%04X", $_), unpack(KEY_TEMPLATE, shift);
434
435     if ($self->{UCA_Version} <= 8) {
436         $view =~ s/ ?0000 ?/|/g;
437     } else {
438         $view =~ s/\b0000\b/|/g;
439     }
440     return "[$view]";
441 }
442
443
444 ##
445 ## arrayref of JCPS   = splitEnt(string to be collated)
446 ## arrayref of arrayref[JCPS, ini_pos, fin_pos] = splitEnt(string, true)
447 ##
448 sub splitEnt
449 {
450     my $self = shift;
451     my $wLen = $_[1];
452
453     my $code = $self->{preprocess};
454     my $norm = $self->{normCode};
455     my $map  = $self->{mapping};
456     my $max  = $self->{maxlength};
457     my $reH  = $self->{rearrangeHash};
458     my $ver9 = $self->{UCA_Version} >= 9;
459
460     my ($str, @buf);
461
462     if ($wLen) {
463         $code and croak "Preprocess breaks character positions. "
464                         . "Don't use with index(), match(), etc.";
465         $norm and croak "Normalization breaks character positions. "
466                         . "Don't use with index(), match(), etc.";
467         $str = $_[0];
468     }
469     else {
470         $str = $_[0];
471         $str = &$code($str) if ref $code;
472         $str = &$norm($str) if ref $norm;
473     }
474
475     # get array of Unicode code point of string.
476     my @src = unpack_U($str);
477
478     # rearrangement:
479     # Character positions are not kept if rearranged,
480     # then neglected if $wLen is true.
481     if ($reH && ! $wLen) {
482         for (my $i = 0; $i < @src; $i++) {
483             if (exists $reH->{ $src[$i] } && $i + 1 < @src) {
484                 ($src[$i], $src[$i+1]) = ($src[$i+1], $src[$i]);
485                 $i++;
486             }
487         }
488     }
489
490     # To remove a character marked as a completely ignorable.
491     for (my $i = 0; $i < @src; $i++) {
492         $src[$i] = undef
493             if _isIllegal($src[$i]) || ($ver9 &&
494                 $map->{ $src[$i] } && @{ $map->{ $src[$i] } } == 0);
495     }
496
497     for (my $i = 0; $i < @src; $i++) {
498         my $jcps = $src[$i];
499         next if ! defined $jcps;
500         my $i_orig = $i;
501
502         if ($max->{$jcps}) { # contract
503             my $temp_jcps = $jcps;
504             my $jcpsLen = 1;
505             my $maxLen = $max->{$jcps};
506
507             for (my $p = $i + 1; $jcpsLen < $maxLen && $p < @src; $p++) {
508                 next if ! defined $src[$p];
509                 $temp_jcps .= CODE_SEP . $src[$p];
510                 $jcpsLen++;
511                 if ($map->{$temp_jcps}) {
512                     $jcps = $temp_jcps;
513                     $i = $p;
514                 }
515             }
516
517         # not-contiguous contraction with Combining Char (cf. UTS#10, S2.1).
518         # This process requires Unicode::Normalize.
519         # If "normalization" is undef, here should be skipped *always*
520         # (in spite of bool value of $CVgetCombinClass),
521         # since canonical ordering cannot be expected.
522         # Blocked combining character should not be contracted.
523
524             if ($self->{normalization})
525             # $self->{normCode} is false in the case of "prenormalized".
526             {
527                 my $preCC = 0;
528                 my $curCC = 0;
529
530                 for (my $p = $i + 1; $p < @src; $p++) {
531                     next if ! defined $src[$p];
532                     $curCC = $CVgetCombinClass->($src[$p]);
533                     last unless $curCC;
534                     my $tail = CODE_SEP . $src[$p];
535                     if ($preCC != $curCC && $map->{$jcps.$tail}) {
536                         $jcps .= $tail;
537                         $src[$p] = undef;
538                     } else {
539                         $preCC = $curCC;
540                     }
541                 }
542             }
543         }
544
545         if ($wLen) {
546             for (; $i + 1 < @src; $i++) {
547                 last if defined $src[$i + 1];
548             }
549         }
550
551         push @buf, $wLen ? [$jcps, $i_orig, $i + 1] : $jcps;
552     }
553     return \@buf;
554 }
555
556
557 ##
558 ## list of VCE = getWt(JCPS)
559 ##
560 sub getWt
561 {
562     my $self = shift;
563     my $u    = shift;
564     my $vbl  = $self->{variable};
565     my $map  = $self->{mapping};
566     my $der  = $self->{derivCode};
567
568     return if !defined $u;
569     return map(_varCE($vbl, $_), @{ $map->{$u} })
570         if $map->{$u};
571
572     # JCPS must not be a contraction, then it's a code point.
573     if (Hangul_SIni <= $u && $u <= Hangul_SFin) {
574         my $hang = $self->{overrideHangul};
575         my @hangulCE;
576         if ($hang) {
577             @hangulCE = map(pack(VCE_TEMPLATE, NON_VAR, @$_), &$hang($u));
578         }
579         elsif (!defined $hang) {
580             @hangulCE = $der->($u);
581         }
582         else {
583             my $max  = $self->{maxlength};
584             my @decH = _decompHangul($u);
585
586             if (@decH == 2) {
587                 my $contract = join(CODE_SEP, @decH);
588                 @decH = ($contract) if $map->{$contract};
589             } else { # must be <@decH == 3>
590                 if ($max->{$decH[0]}) {
591                     my $contract = join(CODE_SEP, @decH);
592                     if ($map->{$contract}) {
593                         @decH = ($contract);
594                     } else {
595                         $contract = join(CODE_SEP, @decH[0,1]);
596                         $map->{$contract} and @decH = ($contract, $decH[2]);
597                     }
598                     # even if V's ignorable, LT contraction is not supported.
599                     # If such a situatution were required, NFD should be used.
600                 }
601                 if (@decH == 3 && $max->{$decH[1]}) {
602                     my $contract = join(CODE_SEP, @decH[1,2]);
603                     $map->{$contract} and @decH = ($decH[0], $contract);
604                 }
605             }
606
607             @hangulCE = map({
608                     $map->{$_} ? @{ $map->{$_} } : $der->($_);
609                 } @decH);
610         }
611         return map _varCE($vbl, $_), @hangulCE;
612     }
613     elsif (CJK_UidIni  <= $u && $u <= CJK_UidFin  ||
614            CJK_ExtAIni <= $u && $u <= CJK_ExtAFin ||
615            CJK_ExtBIni <= $u && $u <= CJK_ExtBFin) {
616         my $cjk  = $self->{overrideCJK};
617         return map _varCE($vbl, $_),
618             $cjk
619                 ? map(pack(VCE_TEMPLATE, NON_VAR, @$_), &$cjk($u))
620                 : defined $cjk && $self->{UCA_Version} <= 8 && $u <= BMP_Max
621                     ? pack(VCE_TEMPLATE, NON_VAR, $u, Min2Wt, Min3Wt, $u)
622                     : $der->($u);
623     }
624     else {
625         return map _varCE($vbl, $_), $der->($u);
626     }
627 }
628
629
630 ##
631 ## string sortkey = getSortKey(string arg)
632 ##
633 sub getSortKey
634 {
635     my $self = shift;
636     my $lev  = $self->{level};
637     my $rEnt = $self->splitEnt(shift); # get an arrayref of JCPS
638     my $ver9 = $self->{UCA_Version} >= 9;
639     my $v2i  = $ver9 && $self->{variable} ne 'non-ignorable';
640
641     my @buf; # weight arrays
642     if ($self->{hangul_terminator}) {
643         my $preHST = '';
644         foreach my $jcps (@$rEnt) {
645             # weird things like VL, TL-contraction are not considered!
646             my $curHST = '';
647             foreach my $u (split /;/, $jcps) {
648                 $curHST .= getHST($u);
649             }
650             if ($preHST && !$curHST || # hangul before non-hangul
651                 $preHST =~ /L\z/ && $curHST =~ /^T/ ||
652                 $preHST =~ /V\z/ && $curHST =~ /^L/ ||
653                 $preHST =~ /T\z/ && $curHST =~ /^[LV]/) {
654
655                 push @buf, $self->getWtHangulTerm();
656             }
657             $preHST = $curHST;
658
659             push @buf, $self->getWt($jcps);
660         }
661         $preHST # end at hangul
662             and push @buf, $self->getWtHangulTerm();
663     }
664     else {
665         foreach my $jcps (@$rEnt) {
666             push @buf, $self->getWt($jcps);
667         }
668     }
669
670     # make sort key
671     my @ret = ([],[],[],[]);
672     my $last_is_variable;
673
674     foreach my $vwt (@buf) {
675         my($var, @wt) = unpack(VCE_TEMPLATE, $vwt);
676         if ($v2i) {
677             if ($var) {
678                 $last_is_variable = TRUE;
679             }
680             elsif (!$wt[0]) { # ignorable
681                 next if $last_is_variable;
682             }
683             else {
684                 $last_is_variable = FALSE;
685             }
686         }
687         foreach my $v (0..$lev-1) {
688             0 < $wt[$v] and push @{ $ret[$v] }, $wt[$v];
689         }
690     }
691
692     # modification of tertiary weights
693     if ($self->{upper_before_lower}) {
694         foreach (@{ $ret[2] }) {
695             if    (0x8 <= $_ && $_ <= 0xC) { $_ -= 6 } # lower
696             elsif (0x2 <= $_ && $_ <= 0x6) { $_ += 6 } # upper
697             elsif ($_ == 0x1C)             { $_ += 1 } # square upper
698             elsif ($_ == 0x1D)             { $_ -= 1 } # square lower
699         }
700     }
701     if ($self->{katakana_before_hiragana}) {
702         foreach (@{ $ret[2] }) {
703             if    (0x0F <= $_ && $_ <= 0x13) { $_ -= 2 } # katakana
704             elsif (0x0D <= $_ && $_ <= 0x0E) { $_ += 5 } # hiragana
705         }
706     }
707
708     if ($self->{backwardsFlag}) {
709         for (my $v = MinLevel; $v <= MaxLevel; $v++) {
710             if ($self->{backwardsFlag} & (1 << $v)) {
711                 @{ $ret[$v-1] } = reverse @{ $ret[$v-1] };
712             }
713         }
714     }
715
716     join LEVEL_SEP, map pack(KEY_TEMPLATE, @$_), @ret;
717 }
718
719
720 ##
721 ## int compare = cmp(string a, string b)
722 ##
723 sub cmp { $_[0]->getSortKey($_[1]) cmp $_[0]->getSortKey($_[2]) }
724 sub eq  { $_[0]->getSortKey($_[1]) eq  $_[0]->getSortKey($_[2]) }
725 sub ne  { $_[0]->getSortKey($_[1]) ne  $_[0]->getSortKey($_[2]) }
726 sub lt  { $_[0]->getSortKey($_[1]) lt  $_[0]->getSortKey($_[2]) }
727 sub le  { $_[0]->getSortKey($_[1]) le  $_[0]->getSortKey($_[2]) }
728 sub gt  { $_[0]->getSortKey($_[1]) gt  $_[0]->getSortKey($_[2]) }
729 sub ge  { $_[0]->getSortKey($_[1]) ge  $_[0]->getSortKey($_[2]) }
730
731 ##
732 ## list[strings] sorted = sort(list[strings] arg)
733 ##
734 sub sort {
735     my $obj = shift;
736     return
737         map { $_->[1] }
738             sort{ $a->[0] cmp $b->[0] }
739                 map [ $obj->getSortKey($_), $_ ], @_;
740 }
741
742
743 sub _derivCE_9 {
744     my $u = shift;
745     my $base =
746         (CJK_UidIni  <= $u && $u <= CJK_UidFin)
747             ? 0xFB40 : # CJK
748         (CJK_ExtAIni <= $u && $u <= CJK_ExtAFin ||
749          CJK_ExtBIni <= $u && $u <= CJK_ExtBFin)
750             ? 0xFB80   # CJK ext.
751             : 0xFBC0;  # others
752
753     my $aaaa = $base + ($u >> 15);
754     my $bbbb = ($u & 0x7FFF) | 0x8000;
755     return
756         pack(VCE_TEMPLATE, NON_VAR, $aaaa, Min2Wt, Min3Wt, $u),
757         pack(VCE_TEMPLATE, NON_VAR, $bbbb,      0,      0, $u);
758 }
759
760 sub _derivCE_8 {
761     my $code = shift;
762     my $aaaa =  0xFF80 + ($code >> 15);
763     my $bbbb = ($code & 0x7FFF) | 0x8000;
764     return
765         pack(VCE_TEMPLATE, NON_VAR, $aaaa, 2, 1, $code),
766         pack(VCE_TEMPLATE, NON_VAR, $bbbb, 0, 0, $code);
767 }
768
769
770 sub getWtHangulTerm {
771     my $self = shift;
772     return _varCE($self->{variable},
773         pack(VCE_TEMPLATE, NON_VAR, $self->{hangul_terminator}, 0,0,0));
774 }
775
776
777 ##
778 ## "hhhh hhhh hhhh" to (dddd, dddd, dddd)
779 ##
780 sub _getHexArray { map hex, $_[0] =~ /([0-9a-fA-F]+)/g }
781
782 #
783 # $code *must* be in Hangul syllable.
784 # Check it before you enter here.
785 #
786 sub _decompHangul {
787     my $code = shift;
788     my $SIndex = $code - Hangul_SBase;
789     my $LIndex = int( $SIndex / Hangul_NCount);
790     my $VIndex = int(($SIndex % Hangul_NCount) / Hangul_TCount);
791     my $TIndex =      $SIndex % Hangul_TCount;
792     return (
793         Hangul_LBase + $LIndex,
794         Hangul_VBase + $VIndex,
795         $TIndex ? (Hangul_TBase + $TIndex) : (),
796     );
797 }
798
799 sub _isIllegal {
800     my $code = shift;
801     return ! defined $code                      # removed
802         || ($code < 0 || 0x10FFFF < $code)      # out of range
803         || (($code & 0xFFFE) == 0xFFFE)         # ??FFF[EF] (cf. utf8.c)
804         || (0xD800 <= $code && $code <= 0xDFFF) # unpaired surrogates
805         || (0xFDD0 <= $code && $code <= 0xFDEF) # other non-characters
806     ;
807 }
808
809 # Hangul Syllable Type
810 sub getHST {
811     my $u = shift;
812     return
813         Hangul_LIni <= $u && $u <= Hangul_LFin || $u == Hangul_LFill ? "L" :
814         Hangul_VIni <= $u && $u <= Hangul_VFin       ? "V" :
815         Hangul_TIni <= $u && $u <= Hangul_TFin       ? "T" :
816         Hangul_SIni <= $u && $u <= Hangul_SFin ?
817             ($u - Hangul_SBase) % Hangul_TCount ? "LVT" : "LV" : "";
818 }
819
820
821 ##
822 ## bool _nonIgnorAtLevel(arrayref weights, int level)
823 ##
824 sub _nonIgnorAtLevel($$)
825 {
826     my $wt = shift;
827     return if ! defined $wt;
828     my $lv = shift;
829     return grep($wt->[$_-1] != 0, MinLevel..$lv) ? TRUE : FALSE;
830 }
831
832 ##
833 ## bool _eqArray(
834 ##    arrayref of arrayref[weights] source,
835 ##    arrayref of arrayref[weights] substr,
836 ##    int level)
837 ## * comparison of graphemes vs graphemes.
838 ##   @$source >= @$substr must be true (check it before call this);
839 ##
840 sub _eqArray($$$)
841 {
842     my $source = shift;
843     my $substr = shift;
844     my $lev = shift;
845
846     for my $g (0..@$substr-1){
847         # Do the $g'th graphemes have the same number of AV weigths?
848         return if @{ $source->[$g] } != @{ $substr->[$g] };
849
850         for my $w (0..@{ $substr->[$g] }-1) {
851             for my $v (0..$lev-1) {
852                 return if $source->[$g][$w][$v] != $substr->[$g][$w][$v];
853             }
854         }
855     }
856     return 1;
857 }
858
859 ##
860 ## (int position, int length)
861 ## int position = index(string, substring, position, [undoc'ed grobal])
862 ##
863 ## With "grobal" (only for the list context),
864 ##  returns list of arrayref[position, length].
865 ##
866 sub index
867 {
868     my $self = shift;
869     my $str  = shift;
870     my $len  = length($str);
871     my $subE = $self->splitEnt(shift);
872     my $pos  = @_ ? shift : 0;
873        $pos  = 0 if $pos < 0;
874     my $grob = shift;
875
876     my $lev  = $self->{level};
877     my $ver9 = $self->{UCA_Version} >= 9;
878     my $v2i  = $self->{variable} ne 'non-ignorable';
879
880     if (! @$subE) {
881         my $temp = $pos <= 0 ? 0 : $len <= $pos ? $len : $pos;
882         return $grob
883             ? map([$_, 0], $temp..$len)
884             : wantarray ? ($temp,0) : $temp;
885     }
886     $len < $pos
887         and return wantarray ? () : NOMATCHPOS;
888     my $strE = $self->splitEnt($pos ? substr($str, $pos) : $str, TRUE);
889     @$strE
890         or return wantarray ? () : NOMATCHPOS;
891
892     my(@strWt, @iniPos, @finPos, @subWt, @g_ret);
893
894     my $last_is_variable;
895     for my $vwt (map $self->getWt($_), @$subE) {
896         my($var, @wt) = unpack(VCE_TEMPLATE, $vwt);
897         my $to_be_pushed = _nonIgnorAtLevel(\@wt,$lev);
898
899         if ($v2i && $ver9) {
900             if ($var) {
901                 $last_is_variable = TRUE;
902             }
903             elsif (!$wt[0]) { # ignorable
904                 $to_be_pushed = FALSE if $last_is_variable;
905             }
906             else {
907                 $last_is_variable = FALSE;
908             }
909         }
910
911         if (@subWt && !$var && !$wt[0]) {
912             push @{ $subWt[-1] }, \@wt if $to_be_pushed;
913         } else {
914             push @subWt, [ \@wt ];
915         }
916     }
917
918     my $count = 0;
919     my $end = @$strE - 1;
920
921     $last_is_variable = FALSE; # reuse
922     for (my $i = 0; $i <= $end; ) { # no $i++
923         my $found_base = 0;
924
925         # fetch a grapheme
926         while ($i <= $end && $found_base == 0) {
927             for my $vwt ($self->getWt($strE->[$i][0])) {
928                 my($var, @wt) = unpack(VCE_TEMPLATE, $vwt);
929                 my $to_be_pushed = _nonIgnorAtLevel(\@wt,$lev);
930
931                 if ($v2i && $ver9) {
932                     if ($var) {
933                         $last_is_variable = TRUE;
934                     }
935                     elsif (!$wt[0]) { # ignorable
936                         $to_be_pushed = FALSE if $last_is_variable;
937                     }
938                     else {
939                         $last_is_variable = FALSE;
940                     }
941                 }
942
943                 if (@strWt && !$var && !$wt[0]) {
944                     push @{ $strWt[-1] }, \@wt if $to_be_pushed;
945                     $finPos[-1] = $strE->[$i][2];
946                 } elsif ($to_be_pushed) {
947                     push @strWt, [ \@wt ];
948                     push @iniPos, $found_base ? NOMATCHPOS : $strE->[$i][1];
949                     $finPos[-1] = NOMATCHPOS if $found_base;
950                     push @finPos, $strE->[$i][2];
951                     $found_base++;
952                 }
953                 # else ===> no-op
954             }
955             $i++;
956         }
957
958         # try to match
959         while ( @strWt > @subWt || (@strWt == @subWt && $i > $end) ) {
960             if ($iniPos[0] != NOMATCHPOS &&
961                     $finPos[$#subWt] != NOMATCHPOS &&
962                         _eqArray(\@strWt, \@subWt, $lev)) {
963                 my $temp = $iniPos[0] + $pos;
964
965                 if ($grob) {
966                     push @g_ret, [$temp, $finPos[$#subWt] - $iniPos[0]];
967                     splice @strWt,  0, $#subWt;
968                     splice @iniPos, 0, $#subWt;
969                     splice @finPos, 0, $#subWt;
970                 }
971                 else {
972                     return wantarray
973                         ? ($temp, $finPos[$#subWt] - $iniPos[0])
974                         :  $temp;
975                 }
976             }
977             shift @strWt;
978             shift @iniPos;
979             shift @finPos;
980         }
981     }
982
983     return $grob
984         ? @g_ret
985         : wantarray ? () : NOMATCHPOS;
986 }
987
988 ##
989 ## scalarref to matching part = match(string, substring)
990 ##
991 sub match
992 {
993     my $self = shift;
994     if (my($pos,$len) = $self->index($_[0], $_[1])) {
995         my $temp = substr($_[0], $pos, $len);
996         return wantarray ? $temp : \$temp;
997         # An lvalue ref \substr should be avoided,
998         # since its value is affected by modification of its referent.
999     }
1000     else {
1001         return;
1002     }
1003 }
1004
1005 ##
1006 ## arrayref matching parts = gmatch(string, substring)
1007 ##
1008 sub gmatch
1009 {
1010     my $self = shift;
1011     my $str  = shift;
1012     my $sub  = shift;
1013     return map substr($str, $_->[0], $_->[1]),
1014                 $self->index($str, $sub, 0, 'g');
1015 }
1016
1017 ##
1018 ## bool subst'ed = subst(string, substring, replace)
1019 ##
1020 sub subst
1021 {
1022     my $self = shift;
1023     my $code = ref $_[2] eq 'CODE' ? $_[2] : FALSE;
1024
1025     if (my($pos,$len) = $self->index($_[0], $_[1])) {
1026         if ($code) {
1027             my $mat = substr($_[0], $pos, $len);
1028             substr($_[0], $pos, $len, $code->($mat));
1029         } else {
1030             substr($_[0], $pos, $len, $_[2]);
1031         }
1032         return TRUE;
1033     }
1034     else {
1035         return FALSE;
1036     }
1037 }
1038
1039 ##
1040 ## int count = gsubst(string, substring, replace)
1041 ##
1042 sub gsubst
1043 {
1044     my $self = shift;
1045     my $code = ref $_[2] eq 'CODE' ? $_[2] : FALSE;
1046     my $cnt = 0;
1047
1048     # Replacement is carried out from the end, then use reverse.
1049     for my $pos_len (reverse $self->index($_[0], $_[1], 0, 'g')) {
1050         if ($code) {
1051             my $mat = substr($_[0], $pos_len->[0], $pos_len->[1]);
1052             substr($_[0], $pos_len->[0], $pos_len->[1], $code->($mat));
1053         } else {
1054             substr($_[0], $pos_len->[0], $pos_len->[1], $_[2]);
1055         }
1056         $cnt++;
1057     }
1058     return $cnt;
1059 }
1060
1061 1;
1062 __END__
1063
1064 =head1 NAME
1065
1066 Unicode::Collate - Unicode Collation Algorithm
1067
1068 =head1 SYNOPSIS
1069
1070   use Unicode::Collate;
1071
1072   #construct
1073   $Collator = Unicode::Collate->new(%tailoring);
1074
1075   #sort
1076   @sorted = $Collator->sort(@not_sorted);
1077
1078   #compare
1079   $result = $Collator->cmp($a, $b); # returns 1, 0, or -1.
1080
1081   # If %tailoring is false (i.e. empty),
1082   # $Collator should do the default collation.
1083
1084 =head1 DESCRIPTION
1085
1086 This module is an implementation
1087 of Unicode Technical Standard #10 (UTS #10)
1088 "Unicode Collation Algorithm."
1089
1090 =head2 Constructor and Tailoring
1091
1092 The C<new> method returns a collator object.
1093
1094    $Collator = Unicode::Collate->new(
1095       UCA_Version => $UCA_Version,
1096       alternate => $alternate, # deprecated: use of 'variable' is recommended.
1097       backwards => $levelNumber, # or \@levelNumbers
1098       entry => $element,
1099       hangul_terminator => $term_primary_weight,
1100       ignoreName => qr/$ignoreName/,
1101       ignoreChar => qr/$ignoreChar/,
1102       katakana_before_hiragana => $bool,
1103       level => $collationLevel,
1104       normalization  => $normalization_form,
1105       overrideCJK => \&overrideCJK,
1106       overrideHangul => \&overrideHangul,
1107       preprocess => \&preprocess,
1108       rearrange => \@charList,
1109       table => $filename,
1110       undefName => qr/$undefName/,
1111       undefChar => qr/$undefChar/,
1112       upper_before_lower => $bool,
1113       variable => $variable,
1114    );
1115
1116 =over 4
1117
1118 =item UCA_Version
1119
1120 If the tracking version number of the older UCA is given,
1121 the older behavior of that tracking version is emulated on collating.
1122 If omitted, the return value of C<UCA_Version()> is used.
1123
1124 The supported tracking version: 8, 9, or 11.
1125
1126 B<This parameter may be removed in the future version,
1127 as switching the algorithm would affect the performance.>
1128
1129 =item backwards
1130
1131 -- see 3.1.2 French Accents, UTS #10.
1132
1133      backwards => $levelNumber or \@levelNumbers
1134
1135 Weights in reverse order; ex. level 2 (diacritic ordering) in French.
1136 If omitted, forwards at all the levels.
1137
1138 =item entry
1139
1140 -- see 3.1 Linguistic Features; 3.2.1 File Format, UTS #10.
1141
1142 If the same character (or a sequence of characters) exists
1143 in the collation element table through C<table>,
1144 mapping to collation elements is overrided.
1145 If it does not exist, the mapping is defined additionally.
1146
1147     entry => <<'ENTRY', # for DUCET v4.0.0 (allkeys-4.0.0.txt)
1148 0063 0068 ; [.0E6A.0020.0002.0063] # ch
1149 0043 0068 ; [.0E6A.0020.0007.0043] # Ch
1150 0043 0048 ; [.0E6A.0020.0008.0043] # CH
1151 006C 006C ; [.0F4C.0020.0002.006C] # ll
1152 004C 006C ; [.0F4C.0020.0007.004C] # Ll
1153 004C 004C ; [.0F4C.0020.0008.004C] # LL
1154 00F1      ; [.0F7B.0020.0002.00F1] # n-tilde
1155 006E 0303 ; [.0F7B.0020.0002.00F1] # n-tilde
1156 00D1      ; [.0F7B.0020.0008.00D1] # N-tilde
1157 004E 0303 ; [.0F7B.0020.0008.00D1] # N-tilde
1158 ENTRY
1159
1160     entry => <<'ENTRY', # for DUCET v4.0.0 (allkeys-4.0.0.txt)
1161 00E6 ; [.0E33.0020.0002.00E6][.0E8B.0020.0002.00E6] # ae ligature as <a><e>
1162 00C6 ; [.0E33.0020.0008.00C6][.0E8B.0020.0008.00C6] # AE ligature as <A><E>
1163 ENTRY
1164
1165 B<NOTE:> The code point in the UCA file format (before C<';'>)
1166 B<must> be a Unicode code point (defined as hexadecimal),
1167 but not a native code point.
1168 So C<0063> must always denote C<U+0063>,
1169 but not a character of C<"\x63">.
1170
1171 Weighting may vary depending on collation element table.
1172 So ensure the weights defined in C<entry> will be consistent with
1173 those in the collation element table loaded via C<table>.
1174
1175 In DUCET v4.0.0, primary weight of C<C> is C<0E60>
1176 and that of C<D> is C<0E6D>. So setting primary weight of C<CH> to C<0E6A>
1177 (as a value between C<0E60> and C<0E6D>)
1178 makes ordering as C<C E<lt> CH E<lt> D>.
1179 Exactly speaking DUCET already has some characters between C<C> and C<D>:
1180 C<small capital C> (C<U+1D04>) with primary weight C<0E64>,
1181 C<c-hook/C-hook> (C<U+0188/U+0187>) with C<0E65>,
1182 and C<c-curl> (C<U+0255>) with C<0E69>.
1183 Then primary weight C<0E6A> for C<CH> makes C<CH>
1184 ordered between C<c-curl> and C<D>.
1185
1186 =item hangul_terminator
1187
1188 -- see Condition B.2. in 7.1.4 Trailing Weights, UTS #10.
1189
1190 If a true value is given (non-zero but should be positive),
1191 it will be added as a terminator primary weight to the end of
1192 every standard Hangul syllable. Secondary and any higher weights
1193 for terminator are set to zero.
1194 If the value is false or C<hangul_terminator> key does not exist,
1195 insertion of terminator weights will not be performed.
1196
1197 Boundaries of Hangul syllables are determined
1198 according to conjoining Jamo behavior in F<the Unicode Standard>
1199 and F<HangulSyllableType.txt>.
1200
1201 B<Implementation Note:>
1202 (1) For expansion mapping (Unicode character mapped
1203 to a sequence of collation elements), a terminator will not be added
1204 between collation elements, even if Hangul syllable boundary exists there.
1205 Addition of terminator is restricted to the next position
1206 to the last collation element.
1207
1208 (2) Non-conjoining Hangul letters
1209 (Compatibility Jamo, halfwidth Jamo, and enclosed letters) are not
1210 automatically terminated with a terminator primary weight.
1211 These characters may need terminator included in a collation element
1212 table beforehand.
1213
1214 =item ignoreName
1215
1216 =item ignoreChar
1217
1218 -- see Completely Ignorable, 3.2.2 Variable Weighting, UTS #10.
1219
1220 Makes the entry in the table completely ignorable;
1221 i.e. as if the weights were zero at all level.
1222
1223 E.g. when 'a' and 'e' are ignorable,
1224 'element' is equal to 'lament' (or 'lmnt').
1225
1226 =item level
1227
1228 -- see 4.3 Form a sort key for each string, UTS #10.
1229
1230 Set the maximum level.
1231 Any higher levels than the specified one are ignored.
1232
1233   Level 1: alphabetic ordering
1234   Level 2: diacritic ordering
1235   Level 3: case ordering
1236   Level 4: tie-breaking (e.g. in the case when variable is 'shifted')
1237
1238   ex.level => 2,
1239
1240 If omitted, the maximum is the 4th.
1241
1242 =item normalization
1243
1244 -- see 4.1 Normalize each input string, UTS #10.
1245
1246 If specified, strings are normalized before preparation of sort keys
1247 (the normalization is executed after preprocess).
1248
1249 A form name C<Unicode::Normalize::normalize()> accepts will be applied
1250 as C<$normalization_form>.
1251 Acceptable names include C<'NFD'>, C<'NFC'>, C<'NFKD'>, and C<'NFKC'>.
1252 See C<Unicode::Normalize::normalize()> for detail.
1253 If omitted, C<'NFD'> is used.
1254
1255 C<normalization> is performed after C<preprocess> (if defined).
1256
1257 Furthermore, special values, C<undef> and C<"prenormalized">, can be used,
1258 though they are not concerned with C<Unicode::Normalize::normalize()>.
1259
1260 If C<undef> (not a string C<"undef">) is passed explicitly
1261 as the value for this key,
1262 any normalization is not carried out (this may make tailoring easier
1263 if any normalization is not desired). Under C<(normalization =E<gt> undef)>,
1264 only contiguous contractions are resolved;
1265 e.g. even if C<A-ring> (and C<A-ring-cedilla>) is ordered after C<Z>,
1266 C<A-cedilla-ring> would be primary equal to C<A>.
1267 In this point,
1268 C<(normalization =E<gt> undef, preprocess =E<gt> sub { NFD(shift) })>
1269 B<is not> equivalent to C<(normalization =E<gt> 'NFD')>.
1270
1271 In the case of C<(normalization =E<gt> "prenormalized")>,
1272 any normalization is not performed, but
1273 non-contiguous contractions with combining characters are performed.
1274 Therefore
1275 C<(normalization =E<gt> 'prenormalized', preprocess =E<gt> sub { NFD(shift) })>
1276 B<is> equivalent to C<(normalization =E<gt> 'NFD')>.
1277 If source strings are finely prenormalized,
1278 C<(normalization =E<gt> 'prenormalized')> may save time for normalization.
1279
1280 Except C<(normalization =E<gt> undef)>,
1281 B<Unicode::Normalize> is required (see also B<CAVEAT>).
1282
1283 =item overrideCJK
1284
1285 -- see 7.1 Derived Collation Elements, UTS #10.
1286
1287 By default, CJK Unified Ideographs are ordered in Unicode codepoint order
1288 (but C<CJK Unified Ideographs> [C<U+4E00> to C<U+9FA5>]  are lesser than
1289 C<CJK Unified Ideographs Extension> [C<U+3400> to C<U+4DB5> and
1290 C<U+20000> to C<U+2A6D6>].
1291
1292 Through C<overrideCJK>, ordering of CJK Unified Ideographs can be overrided.
1293
1294 ex. CJK Unified Ideographs in the JIS code point order.
1295
1296   overrideCJK => sub {
1297       my $u = shift;             # get a Unicode codepoint
1298       my $b = pack('n', $u);     # to UTF-16BE
1299       my $s = your_unicode_to_sjis_converter($b); # convert
1300       my $n = unpack('n', $s);   # convert sjis to short
1301       [ $n, 0x20, 0x2, $u ];     # return the collation element
1302   },
1303
1304 ex. ignores all CJK Unified Ideographs.
1305
1306   overrideCJK => sub {()}, # CODEREF returning empty list
1307
1308    # where ->eq("Pe\x{4E00}rl", "Perl") is true
1309    # as U+4E00 is a CJK Unified Ideograph and to be ignorable.
1310
1311 If C<undef> is passed explicitly as the value for this key,
1312 weights for CJK Unified Ideographs are treated as undefined.
1313 But assignment of weight for CJK Unified Ideographs
1314 in table or C<entry> is still valid.
1315
1316 =item overrideHangul
1317
1318 -- see 7.1 Derived Collation Elements, UTS #10.
1319
1320 By default, Hangul Syllables are decomposed into Hangul Jamo,
1321 even if C<(normalization =E<gt> undef)>.
1322 But the mapping of Hangul Syllables may be overrided.
1323
1324 This tag works like C<overrideCJK>, so see there for examples.
1325
1326 If you want to override the mapping of Hangul Syllables,
1327 NFD, NFKD, and FCD are not appropriate,
1328 since they will decompose Hangul Syllables before overriding.
1329
1330 If C<undef> is passed explicitly as the value for this key,
1331 weight for Hangul Syllables is treated as undefined
1332 without decomposition into Hangul Jamo.
1333 But definition of weight for Hangul Syllables
1334 in table or C<entry> is still valid.
1335
1336 =item preprocess
1337
1338 -- see 5.1 Preprocessing, UTS #10.
1339
1340 If specified, the coderef is used to preprocess
1341 before the formation of sort keys.
1342
1343 ex. dropping English articles, such as "a" or "the".
1344 Then, "the pen" is before "a pencil".
1345
1346      preprocess => sub {
1347            my $str = shift;
1348            $str =~ s/\b(?:an?|the)\s+//gi;
1349            return $str;
1350         },
1351
1352 C<preprocess> is performed before C<normalization> (if defined).
1353
1354 =item rearrange
1355
1356 -- see 3.1.3 Rearrangement, UTS #10.
1357
1358 Characters that are not coded in logical order and to be rearranged.
1359 By default,
1360
1361     rearrange => [ 0x0E40..0x0E44, 0x0EC0..0x0EC4 ],
1362
1363 If you want to disallow any rearrangement,
1364 pass C<undef> or C<[]> (a reference to an empty list)
1365 as the value for this key.
1366
1367 B<According to the version 9 of UCA, this parameter shall not be used;
1368 but it is not warned at present.>
1369
1370 =item table
1371
1372 -- see 3.2 Default Unicode Collation Element Table, UTS #10.
1373
1374 You can use another collation element table if desired.
1375
1376 The table file should locate in the F<Unicode/Collate> directory
1377 on C<@INC>. Say, if the filename is F<Foo.txt>
1378 the table file is searched as F<Unicode/Collate/Foo.txt> in <@INC>.
1379
1380 By default, F<allkeys.txt> (as the filename of DUCET) is used.
1381
1382 If C<undef> is passed explicitly as the value for this key,
1383 no file is read (but you can define collation elements via C<entry>).
1384
1385 A typical way to define a collation element table
1386 without any file of table:
1387
1388    $onlyABC = Unicode::Collate->new(
1389        table => undef,
1390        entry => << 'ENTRIES',
1391 0061 ; [.0101.0020.0002.0061] # LATIN SMALL LETTER A
1392 0041 ; [.0101.0020.0008.0041] # LATIN CAPITAL LETTER A
1393 0062 ; [.0102.0020.0002.0062] # LATIN SMALL LETTER B
1394 0042 ; [.0102.0020.0008.0042] # LATIN CAPITAL LETTER B
1395 0063 ; [.0103.0020.0002.0063] # LATIN SMALL LETTER C
1396 0043 ; [.0103.0020.0008.0043] # LATIN CAPITAL LETTER C
1397 ENTRIES
1398     );
1399
1400 =item undefName
1401
1402 =item undefChar
1403
1404 -- see 6.3.4 Reducing the Repertoire, UTS #10.
1405
1406 Undefines the collation element as if it were unassigned in the table.
1407 This reduces the size of the table.
1408 If an unassigned character appears in the string to be collated,
1409 the sort key is made from its codepoint
1410 as a single-character collation element,
1411 as it is greater than any other assigned collation elements
1412 (in the codepoint order among the unassigned characters).
1413 But, it'd be better to ignore characters
1414 unfamiliar to you and maybe never used.
1415
1416 ex. Collation weights for beyond-BMP characters are not stored in object:
1417
1418     undefChar => qr/[^\0-\x{fffd}]/,
1419
1420 =item katakana_before_hiragana
1421
1422 =item upper_before_lower
1423
1424 -- see 6.6 Case Comparisons; 7.3.1 Tertiary Weight Table, UTS #10.
1425
1426 By default, lowercase is before uppercase
1427 and hiragana is before katakana.
1428
1429 If the tag is made true, this is reversed.
1430
1431 B<NOTE>: These tags simplemindedly assume
1432 any lowercase/uppercase or hiragana/katakana distinctions
1433 must occur in level 3, and their weights at level 3
1434 must be same as those mentioned in 7.3.1, UTS #10.
1435 If you define your collation elements which violate this requirement,
1436 these tags don't work validly.
1437
1438 =item variable
1439
1440 =item alternate
1441
1442 -- see 3.2.2 Variable Weighting, UTS #10.
1443
1444 (the title in UCA version 8: Alternate Weighting)
1445
1446 This key allows to variable weighting for variable collation elements,
1447 which are marked with an ASTERISK in the table
1448 (NOTE: Many punction marks and symbols are variable in F<allkeys.txt>).
1449
1450    variable => 'blanked', 'non-ignorable', 'shifted', or 'shift-trimmed'.
1451
1452 These names are case-insensitive.
1453 By default (if specification is omitted), 'shifted' is adopted.
1454
1455    'Blanked'        Variable elements are made ignorable at levels 1 through 3;
1456                     considered at the 4th level.
1457
1458    'Non-Ignorable'  Variable elements are not reset to ignorable.
1459
1460    'Shifted'        Variable elements are made ignorable at levels 1 through 3
1461                     their level 4 weight is replaced by the old level 1 weight.
1462                     Level 4 weight for Non-Variable elements is 0xFFFF.
1463
1464    'Shift-Trimmed'  Same as 'shifted', but all FFFF's at the 4th level
1465                     are trimmed.
1466
1467 For backward compatibility, C<alternate> can be used as an alias
1468 for C<variable>.
1469
1470 =back
1471
1472 =head2 Methods for Collation
1473
1474 =over 4
1475
1476 =item C<@sorted = $Collator-E<gt>sort(@not_sorted)>
1477
1478 Sorts a list of strings.
1479
1480 =item C<$result = $Collator-E<gt>cmp($a, $b)>
1481
1482 Returns 1 (when C<$a> is greater than C<$b>)
1483 or 0 (when C<$a> is equal to C<$b>)
1484 or -1 (when C<$a> is lesser than C<$b>).
1485
1486 =item C<$result = $Collator-E<gt>eq($a, $b)>
1487
1488 =item C<$result = $Collator-E<gt>ne($a, $b)>
1489
1490 =item C<$result = $Collator-E<gt>lt($a, $b)>
1491
1492 =item C<$result = $Collator-E<gt>le($a, $b)>
1493
1494 =item C<$result = $Collator-E<gt>gt($a, $b)>
1495
1496 =item C<$result = $Collator-E<gt>ge($a, $b)>
1497
1498 They works like the same name operators as theirs.
1499
1500    eq : whether $a is equal to $b.
1501    ne : whether $a is not equal to $b.
1502    lt : whether $a is lesser than $b.
1503    le : whether $a is lesser than $b or equal to $b.
1504    gt : whether $a is greater than $b.
1505    ge : whether $a is greater than $b or equal to $b.
1506
1507 =item C<$sortKey = $Collator-E<gt>getSortKey($string)>
1508
1509 -- see 4.3 Form a sort key for each string, UTS #10.
1510
1511 Returns a sort key.
1512
1513 You compare the sort keys using a binary comparison
1514 and get the result of the comparison of the strings using UCA.
1515
1516    $Collator->getSortKey($a) cmp $Collator->getSortKey($b)
1517
1518       is equivalent to
1519
1520    $Collator->cmp($a, $b)
1521
1522 =item C<$sortKeyForm = $Collator-E<gt>viewSortKey($string)>
1523
1524    use Unicode::Collate;
1525    my $c = Unicode::Collate->new();
1526    print $c->viewSortKey("Perl"),"\n";
1527
1528    # output:
1529    # [0B67 0A65 0B7F 0B03 | 0020 0020 0020 0020 | 0008 0002 0002 0002 | FFFF FFFF FFFF FFFF]
1530    #  Level 1               Level 2               Level 3               Level 4
1531
1532     (If C<UCA_Version> is 8, the output is slightly different.)
1533
1534 =back
1535
1536 =head2 Methods for Searching
1537
1538 B<DISCLAIMER:> If C<preprocess> or C<normalization> tag is true
1539 for C<$Collator>, calling these methods (C<index>, C<match>, C<gmatch>,
1540 C<subst>, C<gsubst>) is croaked,
1541 as the position and the length might differ
1542 from those on the specified string.
1543 (And C<rearrange> and C<hangul_terminator> tags are neglected.)
1544
1545 The C<match>, C<gmatch>, C<subst>, C<gsubst> methods work
1546 like C<m//>, C<m//g>, C<s///>, C<s///g>, respectively,
1547 but they are not aware of any pattern, but only a literal substring.
1548
1549 =over 4
1550
1551 =item C<$position = $Collator-E<gt>index($string, $substring[, $position])>
1552
1553 =item C<($position, $length) = $Collator-E<gt>index($string, $substring[, $position])>
1554
1555 If C<$substring> matches a part of C<$string>, returns
1556 the position of the first occurrence of the matching part in scalar context;
1557 in list context, returns a two-element list of
1558 the position and the length of the matching part.
1559
1560 If C<$substring> does not match any part of C<$string>,
1561 returns C<-1> in scalar context and
1562 an empty list in list context.
1563
1564 e.g. you say
1565
1566   my $Collator = Unicode::Collate->new( normalization => undef, level => 1 );
1567                                      # (normalization => undef) is REQUIRED.
1568   my $str = "Ich muß studieren Perl.";
1569   my $sub = "MÜSS";
1570   my $match;
1571   if (my($pos,$len) = $Collator->index($str, $sub)) {
1572       $match = substr($str, $pos, $len);
1573   }
1574
1575 and get C<"muß"> in C<$match> since C<"muß">
1576 is primary equal to C<"MÜSS">. 
1577
1578 =item C<$match_ref = $Collator-E<gt>match($string, $substring)>
1579
1580 =item C<($match)   = $Collator-E<gt>match($string, $substring)>
1581
1582 If C<$substring> matches a part of C<$string>, in scalar context, returns
1583 B<a reference to> the first occurrence of the matching part
1584 (C<$match_ref> is always true if matches,
1585 since every reference is B<true>);
1586 in list context, returns the first occurrence of the matching part.
1587
1588 If C<$substring> does not match any part of C<$string>,
1589 returns C<undef> in scalar context and
1590 an empty list in list context.
1591
1592 e.g.
1593
1594     if ($match_ref = $Collator->match($str, $sub)) { # scalar context
1595         print "matches [$$match_ref].\n";
1596     } else {
1597         print "doesn't match.\n";
1598     }
1599
1600      or 
1601
1602     if (($match) = $Collator->match($str, $sub)) { # list context
1603         print "matches [$match].\n";
1604     } else {
1605         print "doesn't match.\n";
1606     }
1607
1608 =item C<@match = $Collator-E<gt>gmatch($string, $substring)>
1609
1610 If C<$substring> matches a part of C<$string>, returns
1611 all the matching parts (or matching count in scalar context).
1612
1613 If C<$substring> does not match any part of C<$string>,
1614 returns an empty list.
1615
1616 =item C<$count = $Collator-E<gt>subst($string, $substring, $replacement)>
1617
1618 If C<$substring> matches a part of C<$string>,
1619 the first occurrence of the matching part is replaced by C<$replacement>
1620 (C<$string> is modified) and return C<$count> (always equals to C<1>).
1621
1622 C<$replacement> can be a C<CODEREF>,
1623 taking the matching part as an argument,
1624 and returning a string to replace the matching part
1625 (a bit similar to C<s/(..)/$coderef-E<gt>($1)/e>).
1626
1627 =item C<$count = $Collator-E<gt>gsubst($string, $substring, $replacement)>
1628
1629 If C<$substring> matches a part of C<$string>,
1630 all the occurrences of the matching part is replaced by C<$replacement>
1631 (C<$string> is modified) and return C<$count>.
1632
1633 C<$replacement> can be a C<CODEREF>,
1634 taking the matching part as an argument,
1635 and returning a string to replace the matching part
1636 (a bit similar to C<s/(..)/$coderef-E<gt>($1)/eg>).
1637
1638 e.g.
1639
1640   my $Collator = Unicode::Collate->new( normalization => undef, level => 1 );
1641                                      # (normalization => undef) is REQUIRED.
1642   my $str = "Camel ass came\x{301}l CAMEL horse cAm\0E\0L...";
1643   $Collator->gsubst($str, "camel", sub { "<b>$_[0]</b>" });
1644
1645   # now $str is "<b>Camel</b> ass <b>came\x{301}l</b> <b>CAMEL</b> horse <b>cAm\0E\0L</b>...";
1646   # i.e., all the camels are made bold-faced.
1647
1648 =back
1649
1650 =head2 Other Methods
1651
1652 =over 4
1653
1654 =item C<%old_tailoring = $Collator-E<gt>change(%new_tailoring)>
1655
1656 Change the value of specified keys and returns the changed part.
1657
1658     $Collator = Unicode::Collate->new(level => 4);
1659
1660     $Collator->eq("perl", "PERL"); # false
1661
1662     %old = $Collator->change(level => 2); # returns (level => 4).
1663
1664     $Collator->eq("perl", "PERL"); # true
1665
1666     $Collator->change(%old); # returns (level => 2).
1667
1668     $Collator->eq("perl", "PERL"); # false
1669
1670 Not all C<(key,value)>s are allowed to be changed.
1671 See also C<@Unicode::Collate::ChangeOK> and C<@Unicode::Collate::ChangeNG>.
1672
1673 In the scalar context, returns the modified collator
1674 (but it is B<not> a clone from the original).
1675
1676     $Collator->change(level => 2)->eq("perl", "PERL"); # true
1677
1678     $Collator->eq("perl", "PERL"); # true; now max level is 2nd.
1679
1680     $Collator->change(level => 4)->eq("perl", "PERL"); # false
1681
1682 =item C<$version = $Collator-E<gt>version()>
1683
1684 Returns the version number (a string) of the Unicode Standard
1685 which the C<table> file used by the collator object is based on.
1686 If the table does not include a version line (starting with C<@version>),
1687 returns C<"unknown">.
1688
1689 =item C<UCA_Version()>
1690
1691 Returns the tracking version number of UTS #10 this module consults.
1692
1693 =item C<Base_Unicode_Version()>
1694
1695 Returns the version number of UTS #10 this module consults.
1696
1697 =back
1698
1699 =head2 EXPORT
1700
1701 None by default.
1702
1703 =head2 CAVEAT
1704
1705 Use of the C<normalization> parameter requires
1706 the B<Unicode::Normalize> module.
1707
1708 If you need not it (say, in the case when you need not
1709 handle any combining characters),
1710 assign C<normalization =E<gt> undef> explicitly.
1711
1712 -- see 6.5 Avoiding Normalization, UTS #10.
1713
1714 =head2 Conformance Test
1715
1716 The Conformance Test for the UCA is available
1717 under L<http://www.unicode.org/Public/UCA/>.
1718
1719 For F<CollationTest_SHIFTED.txt>,
1720 a collator via C<Unicode::Collate-E<gt>new( )> should be used;
1721 for F<CollationTest_NON_IGNORABLE.txt>, a collator via
1722 C<Unicode::Collate-E<gt>new(variable =E<gt> "non-ignorable", level =E<gt> 3)>.
1723
1724 B<Unicode::Normalize is required to try The Conformance Test.>
1725
1726 =head1 AUTHOR
1727
1728 SADAHIRO Tomoyuki <SADAHIRO@cpan.org>
1729
1730   http://homepage1.nifty.com/nomenclator/perl/
1731
1732   Copyright(C) 2001-2004, SADAHIRO Tomoyuki. Japan. All rights reserved.
1733
1734   This library is free software; you can redistribute it
1735   and/or modify it under the same terms as Perl itself.
1736
1737 =head1 SEE ALSO
1738
1739 =over 4
1740
1741 =item Unicode Collation Algorithm - UTS #10
1742
1743 L<http://www.unicode.org/reports/tr10/>
1744
1745 =item The Default Unicode Collation Element Table (DUCET)
1746
1747 L<http://www.unicode.org/Public/UCA/latest/allkeys.txt>
1748
1749 =item The conformance test for the UCA
1750
1751 L<http://www.unicode.org/Public/UCA/latest/CollationTest.html>
1752
1753 L<http://www.unicode.org/Public/UCA/latest/CollationTest.zip>
1754
1755 =item Hangul Syllable Type
1756
1757 L<http://www.unicode.org/Public/UNIDATA/HangulSyllableType.txt>
1758
1759 =item Unicode Normalization Forms - UAX #15
1760
1761 L<http://www.unicode.org/reports/tr15/>
1762
1763 =item L<Unicode::Normalize>
1764
1765 =back
1766
1767 =cut