Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Numbers_Words
4
 *
5
 * PHP version 4
6
 *
7
 * Copyright (c) 1997-2006 The PHP Group
8
 *
9
 * This source file is subject to version 3.0 of the PHP license,
10
 * that is bundled with this package in the file LICENSE, and is
11
 * available at through the world-wide-web at
12
 * http://www.php.net/license/3_0.txt.
13
 * If you did not receive a copy of the PHP license and are unable to
14
 * obtain it through the world-wide-web, please send a note to
15
 * license@php.net so we can mail you a copy immediately.
16
 *
17
 * @category Numbers
18
 * @package  Numbers_Words
19
 * @author   Kouber Saparev <kouber@php.net>
20
 * @license  PHP 3.0 http://www.php.net/license/3_0.txt
21
 * @version  CVS: $Id: lang.bg.php 269608 2008-11-24 14:41:17Z clockwerx $
22
 * @link     http://pear.php.net/package/Numbers_Words
23
 */
24
 
25
/**
26
 * Include needed files
27
 */
28
require_once "Numbers/Words.php";
29
 
30
/**
31
 * Class for translating numbers into Bulgarian.
32
 *
33
 * @category Numbers
34
 * @package  Numbers_Words
35
 * @author   Kouber Saparev <kouber@php.net>
36
 * @license  PHP 3.0 http://www.php.net/license/3_0.txt
37
 * @link     http://pear.php.net/package/Numbers_Words
38
 */
39
class Numbers_Words_bg extends Numbers_Words
40
{
41
 
42
    // {{{ properties
43
 
44
    /**
45
     * Locale name.
46
     * @var string
47
     * @access public
48
     */
49
    var $locale = 'bg';
50
 
51
    /**
52
     * Language name in English.
53
     * @var string
54
     * @access public
55
     */
56
    var $lang = 'Bulgarian';
57
 
58
    /**
59
     * Native language name.
60
     * @var string
61
     * @access public
62
     */
63
    var $lang_native = 'Áúëãàðñêè';
64
 
65
    /**
66
     * Some miscellaneous words and language constructs.
67
     * @var string
68
     * @access private
69
     */
70
    var $_misc_strings = array(
71
        'deset'=>'äåñåò',           // "ten"
72
        'edinadeset'=>'åäèíàäåñåò', // "eleven"
73
        'na'=>'íà',                 // liaison particle for 12 to 19
74
        'sto'=>'ñòî',               // "hundred"
75
        'sta'=>'ñòà',               // suffix for 2 and 3 hundred
76
        'stotin'=>'ñòîòèí',         // suffix for 4 to 9 hundred
77
        'hiliadi'=>'õèëÿäè'         // plural form of "thousand"
78
    );
79
 
80
 
81
    /**
82
     * The words for digits (except zero). Note that, there are three genders for them (neuter, masculine and feminine).
83
     * The words for 3 to 9 (masculine) and for 2 to 9 (feminine) are the same as neuter, so they're filled
84
     * in the _initDigits() method, which is invoked from the constructor.
85
     * @var string
86
     * @access private
87
     */
88
    var $_digits = array(
89
        0=>array(1=>"åäíî", "äâå", "òðè", "÷åòèðè", "ïåò", "øåñò", "ñåäåì", "îñåì", "äåâåò"), // neuter
90
        1=>array(1=>'åäèí', 'äâà'),                                                           // masculine
91
       -1=>array(1=>'åäíà')                                                                   // feminine
92
    );
93
 
94
    /**
95
     * A flag, that determines if the _digits array is filled for masculine and feminine genders.
96
     * @var string
97
     * @access private
98
     */
99
    var $_digits_initialized = false;
100
 
101
    /**
102
     * A flag, that determines if the "and" word is placed already before the last non-empty group of digits.
103
     * @var string
104
     * @access private
105
     */
106
    var $_last_and = false;
107
 
108
    /**
109
     * The word for zero.
110
     * @var string
111
     * @access private
112
     */
113
    var $_zero = 'íóëà';
114
 
115
    /**
116
     * The word for infinity.
117
     * @var string
118
     * @access private
119
     */
120
    var $_infinity = 'áåçêðàéíîñò';
121
 
122
    /**
123
     * The word for the "and" language construct.
124
     * @var string
125
     * @access private
126
     */
127
    var $_and = 'è';
128
 
129
    /**
130
     * The word separator.
131
     * @var string
132
     * @access private
133
     */
134
    var $_sep = ' ';
135
 
136
    /**
137
     * The word for the minus sign.
138
     * @var string
139
     * @access private
140
     */
141
    var $_minus = 'ìèíóñ'; // minus sign
142
 
143
    /**
144
     * The plural suffix (except for thousand).
145
     * @var string
146
     * @access private
147
     */
148
    var $_plural = 'à'; // plural suffix
149
 
150
    /**
151
     * The suffixes for exponents (singular).
152
     * @var array
153
     * @access private
154
     */
155
    var $_exponent = array(
156
 
157
          3 => 'õèëÿäà',
158
          6 => 'ìèëèîí',
159
          9 => 'ìèëèàðä',
160
         12 => 'òðèëèîí',
161
         15 => 'êâàäðèëèîí',
162
         18 => 'êâèíòèëèîí',
163
         21 => 'ñåêñòèëèîí',
164
         24 => 'ñåïòèëèîí',
165
         27 => 'îêòèëèîí',
166
         30 => 'íîíàëèîí',
167
         33 => 'äåêàëèîí',
168
         36 => 'óíäåêàëèîí',
169
         39 => 'äóîäåêàëèîí',
170
         42 => 'òðåäåêàëèîí',
171
         45 => 'êâàòîðäåêàëèîí',
172
         48 => 'êâèíòäåêàëèîí',
173
         51 => 'ñåêñäåêàëèîí',
174
         54 => 'ñåïòäåêàëèîí',
175
         57 => 'îêòîäåêàëèîí',
176
         60 => 'íîâåìäåêàëèîí',
177
         63 => 'âèãèíòèëèîí',
178
         66 => 'óíâèãèíòèëèîí',
179
         69 => 'äóîâèãèíòèëèîí',
180
         72 => 'òðåâèãèíòèëèîí',
181
         75 => 'êâàòîðâèãèíòèëèîí',
182
         78 => 'êâèíâèãèíòèëèîí',
183
         81 => 'ñåêñâèãèíòèëèîí',
184
         84 => 'ñåïòåíâèãèíòèëèîí',
185
         87 => 'îêòîâèãèíòèëèîí',
186
         90 => 'íîâåìâèãèíòèëèîí',
187
         93 => 'òðèãèíòèëèîí',
188
         96 => 'óíòðèãèíòèëèîí',
189
         99 => 'äóîòðèãèíòèëèîí',
190
        102 => 'òðåòðèãèíòèëèîí',
191
        105 => 'êâàòîðòðèãèíòèëèîí',
192
        108 => 'êâèíòðèãèíòèëèîí',
193
        111 => 'ñåêñòðèãèíòèëèîí',
194
        114 => 'ñåïòåíòðèãèíòèëèîí',
195
        117 => 'îêòîòðèãèíòèëèîí',
196
        120 => 'íîâåìòðèãèíòèëèîí',
197
        123 => 'êâàäðàãèíòèëèîí',
198
        126 => 'óíêâàäðàãèíòèëèîí',
199
        129 => 'äóîêâàäðàãèíòèëèîí',
200
        132 => 'òðåêâàäðàãèíòèëèîí',
201
        135 => 'êâàòîðêâàäðàãèíòèëèîí',
202
        138 => 'êâèíêâàäðàãèíòèëèîí',
203
        141 => 'ñåêñêâàäðàãèíòèëèîí',
204
        144 => 'ñåïòåíêâàäðàãèíòèëèîí',
205
        147 => 'îêòîêâàäðàãèíòèëèîí',
206
        150 => 'íîâåìêâàäðàãèíòèëèîí',
207
        153 => 'êâèíêâàãèíòèëèîí',
208
        156 => 'óíêâèíêàãèíòèëèîí',
209
        159 => 'äóîêâèíêàãèíòèëèîí',
210
        162 => 'òðåêâèíêàãèíòèëèîí',
211
        165 => 'êâàòîðêâèíêàãèíòèëèîí',
212
        168 => 'êâèíêâèíêàãèíòèëèîí',
213
        171 => 'ñåêñêâèíêàãèíòèëèîí',
214
        174 => 'ñåïòåíêâèíêàãèíòèëèîí',
215
        177 => 'îêòîêâèíêàãèíòèëèîí',
216
        180 => 'íîâåìêâèíêàãèíòèëèîí',
217
        183 => 'ñåêñàãèíòèëèîí',
218
        186 => 'óíñåêñàãèíòèëèîí',
219
        189 => 'äóîñåêñàãèíòèëèîí',
220
        192 => 'òðåñåêñàãèíòèëèîí',
221
        195 => 'êâàòîðñåêñàãèíòèëèîí',
222
        198 => 'êâèíñåêñàãèíòèëèîí',
223
        201 => 'ñåêññåêñàãèíòèëèîí',
224
        204 => 'ñåïòåíñåêñàãèíòèëèîí',
225
        207 => 'îêòîñåêñàãèíòèëèîí',
226
        210 => 'íîâåìñåêñàãèíòèëèîí',
227
        213 => 'ñåïòàãèíòèëèîí',
228
        216 => 'óíñåïòàãèíòèëèîí',
229
        219 => 'äóîñåïòàãèíòèëèîí',
230
        222 => 'òðåñåïòàãèíòèëèîí',
231
        225 => 'êâàòîðñåïòàãèíòèëèîí',
232
        228 => 'êâèíñåïòàãèíòèëèîí',
233
        231 => 'ñåêññåïòàãèíòèëèîí',
234
        234 => 'ñåïòåíñåïòàãèíòèëèîí',
235
        237 => 'îêòîñåïòàãèíòèëèîí',
236
        240 => 'íîâåìñåïòàãèíòèëèîí',
237
        243 => 'îêòîãèíòèëèîí',
238
        246 => 'óíîêòîãèíòèëèîí',
239
        249 => 'äóîîêòîãèíòèëèîí',
240
        252 => 'òðåîêòîãèíòèëèîí',
241
        255 => 'êâàòîðîêòîãèíòèëèîí',
242
        258 => 'êâèíîêòîãèíòèëèîí',
243
        261 => 'ñåêñîêòîãèíòèëèîí',
244
        264 => 'ñåïòîêòîãèíòèëèîí',
245
        267 => 'îêòîîêòîãèíòèëèîí',
246
        270 => 'íîâåìîêòîãèíòèëèîí',
247
        273 => 'íîíàãèíòèëèîí',
248
        276 => 'óííîíàãèíòèëèîí',
249
        279 => 'äóîíîíàãèíòèëèîí',
250
        282 => 'òðåíîíàãèíòèëèîí',
251
        285 => 'êâàòîðíîíàãèíòèëèîí',
252
        288 => 'êâèííîíàãèíòèëèîí',
253
        291 => 'ñåêñíîíàãèíòèëèîí',
254
        294 => 'ñåïòåííîíàãèíòèëèîí',
255
        297 => 'îêòîíîíàãèíòèëèîí',
256
        300 => 'íîâåìíîíàãèíòèëèîí',
257
        303 => 'öåíòèëèîí'
258
    );
259
    // }}}
260
 
261
    // {{{ Numbers_Words_bg()
262
 
263
    /**
264
     * The class constructor, used for calling the _initDigits method.
265
     *
266
     * @return void
267
     *
268
     * @access public
269
     * @author Kouber Saparev <kouber@php.net>
270
     * @see function _initDigits
271
     */
272
    function Numbers_Words_bg()
273
    {
274
        $this->_initDigits();
275
    }
276
    // }}}
277
 
278
    // {{{ _initDigits()
279
 
280
    /**
281
     * Fills the _digits array for masculine and feminine genders with
282
     * corresponding references to neuter words (when they're the same).
283
     *
284
     * @return void
285
     *
286
     * @access private
287
     * @author Kouber Saparev <kouber@php.net>
288
     */
289
    function _initDigits()
290
    {
291
        if (!$this->_digits_initialized) {
292
            for ($i=3; $i<=9; $i++) {
293
                $this->_digits[1][$i] =& $this->_digits[0][$i];
294
            }
295
            for ($i=2; $i<=9; $i++) {
296
                $this->_digits[-1][$i] =& $this->_digits[0][$i];
297
            }
298
            $this->_digits_initialized = true;
299
        }
300
    }
301
    // }}}
302
 
303
    // {{{ _splitNumber()
304
 
305
    /**
306
     * Split a number to groups of three-digit numbers.
307
     *
308
     * @param mixed $num An integer or its string representation
309
     *                   that need to be split
310
     *
311
     * @return array  Groups of three-digit numbers.
312
     *
313
     * @access private
314
     * @author Kouber Saparev <kouber@php.net>
315
     * @since  PHP 4.2.3
316
     */
317
    function _splitNumber($num)
318
    {
319
        if (is_string($num)) {
320
            $ret = array();
321
 
322
            $strlen = strlen($num);
323
            $first  = substr($num, 0, $strlen%3);
324
 
325
            preg_match_all('/\d{3}/', substr($num, $strlen%3, $strlen), $m);
326
 
327
            $ret =& $m[0];
328
            if ($first) {
329
                array_unshift($ret, $first);
330
            }
331
            return $ret;
332
        }
333
 
334
        return explode(' ', number_format($num, 0, '', ' ')); // a faster version for integers
335
    }
336
    // }}}
337
 
338
    // {{{ _showDigitsGroup()
339
 
340
    /**
341
     * Converts a three-digit number to its word representation
342
     * in Bulgarian language.
343
     *
344
     * @param integer $num    An integer between 1 and 999 inclusive.
345
     * @param integer $gender An integer which represents the gender of
346
     *                                                     the current digits group.
347
     *                                                     0 - neuter
348
     *                                                     1 - masculine
349
     *                                                    -1 - feminine
350
     * @param boolean $last   A flag that determines if the current digits group
351
     *                        is the last one.
352
     *
353
     * @return string   The words for the given number.
354
     *
355
     * @access private
356
     * @author Kouber Saparev <kouber@php.net>
357
     */
358
    function _showDigitsGroup($num, $gender = 0, $last = false)
359
    {
360
        /* A storage array for the return string.
361
             Positions 1, 3, 5 are intended for digit words
362
             and everything else (0, 2, 4) for "and" words.
363
             Both of the above types are optional, so the size of
364
             the array may vary.
365
        */
366
        $ret = array();
367
 
368
        // extract the value of each digit from the three-digit number
369
        $e = $num%10;                  // ones
370
        $d = ($num-$e)%100/10;         // tens
371
        $s = ($num-$d*10-$e)%1000/100; // hundreds
372
 
373
        // process the "hundreds" digit.
374
        if ($s) {
375
            switch ($s) {
376
            case 1:
377
                $ret[1] = $this->_misc_strings['sto'];
378
                break;
379
            case 2:
380
            case 3:
381
                $ret[1] = $this->_digits[0][$s].$this->_misc_strings['sta'];
382
                break;
383
            default:
384
                $ret[1] = $this->_digits[0][$s].$this->_misc_strings['stotin'];
385
            }
386
        }
387
 
388
        // process the "tens" digit, and optionally the "ones" digit.
389
        if ($d) {
390
            // in the case of 1, the "ones" digit also must be processed
391
            if ($d==1) {
392
                if (!$e) {
393
                    $ret[3] = $this->_misc_strings['deset']; // ten
394
                } else {
395
                    if ($e==1) {
396
                        $ret[3] = $this->_misc_strings['edinadeset']; // eleven
397
                    } else {
398
                        $ret[3] = $this->_digits[1][$e].$this->_misc_strings['na'].$this->_misc_strings['deset']; // twelve - nineteen
399
                    }
400
                    // the "ones" digit is alredy processed, so skip a second processment
401
                    $e = 0;
402
                }
403
            } else {
404
                $ret[3] = $this->_digits[1][$d].$this->_misc_strings['deset']; // twenty - ninety
405
            }
406
        }
407
 
408
        // process the "ones" digit
409
        if ($e) {
410
            $ret[5] = $this->_digits[$gender][$e];
411
        }
412
 
413
        // put "and" where needed
414
        if (count($ret)>1) {
415
            if ($e) {
416
                $ret[4] = $this->_and;
417
            } else {
418
                $ret[2] = $this->_and;
419
            }
420
        }
421
 
422
        // put "and" optionally in the case this is the last non-empty group
423
        if ($last) {
424
            if (!$s||count($ret)==1) {
425
                $ret[0] = $this->_and;
426
            }
427
            $this->_last_and = true;
428
        }
429
 
430
        // sort the return array so that "and" constructs go to theirs appropriate places
431
        ksort($ret);
432
 
433
        return implode($this->_sep, $ret);
434
    }
435
    // }}}
436
 
437
    // {{{ toWords()
438
 
439
    /**
440
     * Converts a number to its word representation
441
     * in Bulgarian language.
442
     *
443
     * @param integer $num An integer between 9.99*-10^302 and 9.99*10^302 (999 centillions)
444
     *                     that need to be converted to words
445
     *
446
     * @return string  The corresponding word representation
447
     *
448
     * @access public
449
     * @author Kouber Saparev <kouber@php.net>
450
     */
451
    function toWords($num = 0)
452
    {
453
        $ret = array();
454
 
455
        $ret_minus = '';
456
 
457
        // check if $num is a valid non-zero number
458
        if (!$num || preg_match('/^-?0+$/', $num) || !preg_match('/^-?\d+$/', $num)) {
459
            return $this->_zero;
460
        }
461
 
462
        // add a minus sign
463
        if (substr($num, 0, 1) == '-') {
464
            $ret_minus = $this->_minus . $this->_sep;
465
 
466
            $num = substr($num, 1);
467
        }
468
 
469
        // if the absolute value is greater than 9.99*10^302, return infinity
470
        if (strlen($num) > 306) {
471
            return $ret_minus . $this->_infinity;
472
        }
473
 
474
        // strip excessive zero signs
475
        $num = ltrim($num, '0');
476
 
477
        // split $num to groups of three-digit numbers
478
        $num_groups = $this->_splitNumber($num);
479
 
480
        $sizeof_numgroups = count($num_groups);
481
 
482
        // go through the groups in reverse order, so that the last group could be determined
483
        for ($i=$sizeof_numgroups-1, $j=1; $i>=0; $i--, $j++) {
484
            if (!isset($ret[$j])) {
485
                $ret[$j] = '';
486
            }
487
 
488
            // what is the corresponding exponent for the current group
489
            $pow = $sizeof_numgroups-$i;
490
 
491
            // skip processment for empty groups
492
            if ($num_groups[$i]!='000') {
493
                if ($num_groups[$i]>1) {
494
                    if ($pow==1) {
495
                        $ret[$j] .= $this->_showDigitsGroup($num_groups[$i], 0, !$this->_last_and && $i).$this->_sep;
496
                        $ret[$j] .= $this->_exponent[($pow-1)*3];
497
                    } elseif ($pow==2) {
498
                        $ret[$j] .= $this->_showDigitsGroup($num_groups[$i], -1, !$this->_last_and && $i).$this->_sep;
499
                        $ret[$j] .= $this->_misc_strings['hiliadi'].$this->_sep;
500
                    } else {
501
                        $ret[$j] .= $this->_showDigitsGroup($num_groups[$i], 1, !$this->_last_and && $i).$this->_sep;
502
                        $ret[$j] .= $this->_exponent[($pow-1)*3].$this->_plural.$this->_sep;
503
                    }
504
                } else {
505
                    if ($pow==1) {
506
                        $ret[$j] .= $this->_showDigitsGroup($num_groups[$i], 0, !$this->_last_and && $i).$this->_sep;
507
                    } elseif ($pow==2) {
508
                        $ret[$j] .= $this->_exponent[($pow-1)*3].$this->_sep;
509
                    } else {
510
                        $ret[$j] .= $this->_digits[1][1].$this->_sep.$this->_exponent[($pow-1)*3].$this->_sep;
511
                    }
512
                }
513
            }
514
        }
515
 
516
        return $ret_minus . rtrim(implode('', array_reverse($ret)), $this->_sep);
517
    }
518
    // }}}
519
}
520
?>