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   943 no locale;
  1         500  
  1         4  
13 1     1   414 use integer;
  1         11  
  1         4  
14 1     1   24 use strict;
  1         1  
  1         15  
15 1     1   5 use Exporter;
  1         1  
  1         42  
16 1     1   4 use vars qw( @ISA @EXPORT $VERSION $DEBUG );
  1         2  
  1         1111  
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 461 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 5 my $level = shift;
89 4         6 @{$table[$level]} = ( undef ) x 256;
  4         76  
90 4         10 @{$table[$level]}[ord ' ', ord "\t"] = (0, 0);
  4         6  
91 4         5 my $i = 1;
92 4         4 my $irow = 0;
93 4         8 while (defined $def_table[$irow])
94             {
95 192         191 my $def_row = $def_table[$irow];
96 192 100 100     377 next if $level <= 2 and $def_row =~ /^ /;
97 174         323 while ($def_row =~ /<([cC].*?)>|(.)/sg)
98             {
99 779         924 my $match = $+;
100 779 100       921 if ($match eq ' ')
101             {
102 150 100       283 if ($level == 1)
103 36         66 { $i++; }
104             }
105             else
106             {
107 629 100       696 if (length $match == 1)
108 617         634 { $table[$level][ord $match] = $i; }
109             else
110             {
111 12         17 $multiple[$level]{$match} = $i;
112 12         18 $regexp[$level] = $match . "|" . $regexp[$level];
113             }
114 629 100       971 if ($level >= 2)
115 337         576 { $i++; }
116             }
117             }
118 174 100       239 $i++ if $level < 2;
119             }
120             continue
121 192         268 { $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 83 my ($a, $b) = (shift, shift);
136 56 50       358 print STDERR "czcmp: $a/$b\n" if DEBUG;
137 56         78 my ($a1, $b1) = ($a, $b);
138 56         57 my $level = 0;
139 56         52 while (1)
140             {
141 284         371 my ($ac, $bc, $a_no, $b_no, $ax, $bx) = ('', '', 0, 0,
142             undef, undef);
143 284 100       348 if ($level == 0)
144             {
145 237   100     505 while (not defined $ax and not $a_no)
146             {
147 240 100       534 $a =~ /$regexp[$level]/sg or $a_no = 1;
148 240         330 $ac = $&;
149             $ax = ( length $ac == 1 ?
150             $table[$level][ord $ac]
151 240 100       518 : ${$multiple[$level]}{$ac} )
  16 50       40  
152             if defined $ac;
153             }
154 237   100     486 while (not defined $bx and not $b_no)
155             {
156 240 100       479 $b =~ /$regexp[$level]/sg or $b_no = 1;
157 240         320 $bc = $&;
158             $bx = ( length $bc == 1 ?
159             $table[$level][ord $bc]
160 240 100       485 : ${$multiple[$level]}{$bc} )
  16 50       41  
161             if defined $bc;
162             }
163             }
164             else
165             {
166 47   100     96 while (not defined $ax and not $a_no)
167             {
168 48 100       125 $a1 =~ /$regexp[$level]/sg or $a_no = 1;
169 48         72 $ac = $&;
170             $ax = ( length $ac == 1 ?
171             $table[$level][ord $ac]
172 48 100       104 : ${$multiple[$level]}{$ac} )
  4 50       10  
173             if defined $ac;
174             }
175 47   100     94 while (not defined $bx and not $b_no)
176             {
177 47 100       113 $b1 =~ /$regexp[$level]/sg or $b_no = 1;
178 47         62 $bc = $&;
179             $bx = ( length $bc == 1 ?
180             $table[$level][ord $bc]
181 47 100       98 : ${$multiple[$level]}{$bc} )
  4 50       10  
182             if defined $bc;
183             }
184             }
185              
186 284 50       345 print STDERR "level $level: ac: $ac -> $ax; bc: $bc -> $bx ($a_no, $b_no)\n" if DEBUG;
187              
188 284 100 100     437 return -1 if $a_no and not $b_no;
189 278 100 100     569 return 1 if not $a_no and $b_no;
190 269 100 66     385 if ($a_no and $b_no)
191             {
192 10 100       12 if ($level == 0)
193 6         7 { $level = 1; next; }
  6         6  
194 4         7 last;
195             }
196              
197 259 100       359 return -1 if ($ax < $bx);
198 243 100       331 return 1 if ($ax > $bx);
199              
200 222 100 66     316 if ($ax == 0 and $bx == 0)
201             {
202 7 100       9 if ($level == 0)
203 4         3 { $level = 1; next; }
  4         6  
204 3         4 $level = 0; next;
  3         3  
205             }
206             }
207 4         7 for $level (2 .. 3)
208             {
209 5         6 while (1)
210             {
211 6         10 my ($ac, $bc, $a_no, $b_no, $ax, $bx)
212             = ('', '', 0, 0, undef, undef);
213 6   100     16 while (not defined $ax and not $a_no)
214             {
215 7 100       45 $a =~ /$regexp[$level]/sg or $a_no = 1;
216 7         11 $ac = $&;
217             $ax = ( length $ac == 1 ?
218             $table[$level][ord $ac]
219 7 100       24 : ${$multiple[$level]}{$ac} )
  1 50       3  
220             if defined $ac;
221             }
222 6   100     17 while (not defined $bx and not $b_no)
223             {
224 6 100       24 $b =~ /$regexp[$level]/sg or $b_no = 1;
225 6         10 $bc = $&;
226             $bx = ( length $bc == 1 ?
227             $table[$level][ord $bc]
228 6 100       14 : ${$multiple[$level]}{$bc} )
  1 50       2  
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     25 return -1 if $a_no and not $b_no;
234 6 50 66     14 return 1 if not $a_no and $b_no;
235 6 100 66     10 if ($a_no and $b_no)
236 1         2 { last; }
237 5 100       14 return -1 if ($ax < $bx);
238 3 100       9 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 614 { sort { my $result = czcmp($a, $b); } @_; }
  56         72  
251              
252             *cscmp = *czcmp;
253             *cssort = *czsort;
254              
255             1;
256              
257             __END__