File Coverage

blib/lib/Cz/Sort.pm
Criterion Covered Total %
statement 104 105 99.0
branch 71 82 86.5
condition 37 42 88.1
subroutine 9 9 100.0
pod 0 4 0.0
total 221 242 91.3


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Cz::Sort - Czech sort
5              
6             =cut
7              
8             #
9             # Here starts the Cz::Sort namespace
10             #
11             package Cz::Sort;
12 1     1   1160 no locale;
  1         611  
  1         5  
13 1     1   510 use integer;
  1         16  
  1         5  
14 1     1   29 use strict;
  1         2  
  1         17  
15 1     1   5 use Exporter;
  1         2  
  1         54  
16 1     1   6 use vars qw( @ISA @EXPORT $VERSION $DEBUG );
  1         2  
  1         1391  
17             @ISA = qw( Exporter );
18              
19             #
20             # We implicitly export czcmp, czsort, cscmp and cssort functions.
21             # Since these are the only ones that can be used by ordinary users,
22             # it should not cause big harm.
23             #
24             @EXPORT = qw( czsort czcmp cssort cscmp );
25              
26             $VERSION = '0.68';
27             $DEBUG = 0;
28 346     346 0 591 sub DEBUG { $DEBUG; }
29              
30             #
31             # The table with sorting definitions.
32             #
33             my @def_table = (
34             'aA áÁ â ãà äÄ ±¡',
35             'bB',
36             'cC æÆ çÇ', 'èÈ',
37             'dD ïÏ ðÐ',
38             'eE éÉ ìÌ ëË êÊ',
39             'fF',
40             'gG',
41             'hH',
42             '',
43             'iI íÍ îÎ',
44             'jJ',
45             'kK',
46             'lL åÅ µ¥ ³£',
47             'mM',
48             'nN ñÑ òÒ',
49             'oO óÓ ôÔ öÖ õÕ',
50             'pP',
51             'qQ',
52             'rR àÀ', 'øØ',
53             'sS ¶¦ ºª', '¹©',
54             'ß',
55             'tT »« þÞ',
56             'uU úÚ ùÙ üÜ ûÛ',
57             'vV',
58             'wW',
59             'xX',
60             'yY ýÝ',
61             'zZ ¿¯ ¼¬', '¾®',
62             '0', '1', '2', '3',
63             '4', '5', '6', '7',
64             '8', '9',
65             ' .,;?!:"`\'',
66             ' -­|/\\()[]<>{}',
67             ' @&§%$',
68             ' _^=+×*÷#¢~',
69             ' ÿ·°¨½¸²',
70             ' ¤',
71             );
72              
73             #
74             # Conversion table will hold four arrays, one for each pass. They will
75             # be created on the fly if they are needed. We also need to hold
76             # information (regexp) about groups of letters that need to be considered
77             # as one character (ch).
78             #
79             my @table = ( );
80             my @regexp = ( '.', '.', '.', '.' );
81             my @multiple = ( {}, {}, {}, {} );
82              
83             #
84             # Make_table will build sorting table for given level.
85             #
86             sub make_table
87             {
88 4     4 0 7 my $level = shift;
89 4         9 @{$table[$level]} = ( undef ) x 256;
  4         96  
90 4         11 @{$table[$level]}[ord ' ', ord "\t"] = (0, 0);
  4         9  
91 4         7 my $i = 1;
92 4         5 my $irow = 0;
93 4         11 while (defined $def_table[$irow])
94             {
95 192         237 my $def_row = $def_table[$irow];
96 192 100 100     494 next if $level <= 2 and $def_row =~ /^ /;
97 174         406 while ($def_row =~ /<([cC].*?)>|(.)/sg)
98             {
99 779         1187 my $match = $+;
100 779 100       1093 if ($match eq ' ')
101             {
102 150 100       337 if ($level == 1)
103 36         76 { $i++; }
104             }
105             else
106             {
107 629 100       833 if (length $match == 1)
108 617         805 { $table[$level][ord $match] = $i; }
109             else
110             {
111 12         20 $multiple[$level]{$match} = $i;
112 12         24 $regexp[$level] = $match . "|" . $regexp[$level];
113             }
114 629 100       1507 if ($level >= 2)
115 337         689 { $i++; }
116             }
117             }
118 174 100       347 $i++ if $level < 2;
119             }
120             continue
121 192         320 { $irow++; }
122             }
123              
124             #
125             # Create the tables now.
126             #
127             for (0 .. 3)
128             { make_table($_); }
129              
130             #
131             # Compare two scalar, according to the tables.
132             #
133             sub czcmp
134             {
135 56     56 0 116 my ($a, $b) = (shift, shift);
136 56 50       76 print STDERR "czcmp: $a/$b\n" if DEBUG;
137 56         92 my ($a1, $b1) = ($a, $b);
138 56         70 my $level = 0;
139 56         67 while (1)
140             {
141 284         493 my ($ac, $bc, $a_no, $b_no, $ax, $bx) = ('', '', 0, 0,
142             undef, undef);
143 284 100       399 if ($level == 0)
144             {
145 237   100     815 while (not defined $ax and not $a_no)
146             {
147 240 100       667 $a =~ /$regexp[$level]/sg or $a_no = 1;
148 240         409 $ac = $&;
149             $ax = ( length $ac == 1 ?
150             $table[$level][ord $ac]
151 240 100       675 : ${$multiple[$level]}{$ac} )
  16 50       53  
152             if defined $ac;
153             }
154 237   100     632 while (not defined $bx and not $b_no)
155             {
156 240 100       576 $b =~ /$regexp[$level]/sg or $b_no = 1;
157 240         403 $bc = $&;
158             $bx = ( length $bc == 1 ?
159             $table[$level][ord $bc]
160 240 100       606 : ${$multiple[$level]}{$bc} )
  16 50       59  
161             if defined $bc;
162             }
163             }
164             else
165             {
166 47   100     119 while (not defined $ax and not $a_no)
167             {
168 48 100       171 $a1 =~ /$regexp[$level]/sg or $a_no = 1;
169 48         127 $ac = $&;
170             $ax = ( length $ac == 1 ?
171             $table[$level][ord $ac]
172 48 100       129 : ${$multiple[$level]}{$ac} )
  4 50       14  
173             if defined $ac;
174             }
175 47   100     118 while (not defined $bx and not $b_no)
176             {
177 47 100       135 $b1 =~ /$regexp[$level]/sg or $b_no = 1;
178 47         74 $bc = $&;
179             $bx = ( length $bc == 1 ?
180             $table[$level][ord $bc]
181 47 100       117 : ${$multiple[$level]}{$bc} )
  4 50       14  
182             if defined $bc;
183             }
184             }
185              
186 284 50       432 print STDERR "level $level: ac: $ac -> $ax; bc: $bc -> $bx ($a_no, $b_no)\n" if DEBUG;
187              
188 284 100 100     517 return -1 if $a_no and not $b_no;
189 278 100 100     697 return 1 if not $a_no and $b_no;
190 269 100 66     452 if ($a_no and $b_no)
191             {
192 10 100       16 if ($level == 0)
193 6         8 { $level = 1; next; }
  6         8  
194 4         8 last;
195             }
196              
197 259 100       431 return -1 if ($ax < $bx);
198 243 100       405 return 1 if ($ax > $bx);
199              
200 222 100 66     387 if ($ax == 0 and $bx == 0)
201             {
202 7 100       14 if ($level == 0)
203 4         4 { $level = 1; next; }
  4         6  
204 3         5 $level = 0; next;
  3         4  
205             }
206             }
207 4         10 for $level (2 .. 3)
208             {
209 5         5 while (1)
210             {
211 6         13 my ($ac, $bc, $a_no, $b_no, $ax, $bx)
212             = ('', '', 0, 0, undef, undef);
213 6   100     19 while (not defined $ax and not $a_no)
214             {
215 7 100       56 $a =~ /$regexp[$level]/sg or $a_no = 1;
216 7         15 $ac = $&;
217             $ax = ( length $ac == 1 ?
218             $table[$level][ord $ac]
219 7 100       26 : ${$multiple[$level]}{$ac} )
  1 50       5  
220             if defined $ac;
221             }
222 6   100     20 while (not defined $bx and not $b_no)
223             {
224 6 100       30 $b =~ /$regexp[$level]/sg or $b_no = 1;
225 6         12 $bc = $&;
226             $bx = ( length $bc == 1 ?
227             $table[$level][ord $bc]
228 6 100       19 : ${$multiple[$level]}{$bc} )
  1 50       3  
229             if defined $bc;
230             }
231            
232 6 50       12 print STDERR "level $level: ac: $ac -> $ax; bc: $bc -> $bx ($a_no, $b_no)\n" if DEBUG;
233 6 50 66     28 return -1 if $a_no and not $b_no;
234 6 50 66     19 return 1 if not $a_no and $b_no;
235 6 100 66     16 if ($a_no and $b_no)
236 1         2 { last; }
237 5 100       16 return -1 if ($ax < $bx);
238 3 100       10 return 1 if ($ax > $bx);
239             }
240             }
241 0         0 return 0;
242             }
243              
244             1;
245              
246             #
247             # Cssort does the real thing.
248             #
249             sub czsort
250 6     6 0 765 { sort { my $result = czcmp($a, $b); } @_; }
  56         91  
251              
252             *cscmp = *czcmp;
253             *cssort = *czsort;
254              
255             1;
256              
257             __END__