[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Parse and evaluate a plural rule. 5 * 6 * UTS #35 Revision 33 7 * http://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Language_Plural_Rules 8 * 9 * @author Niklas Laxström, Tim Starling 10 * 11 * @copyright Copyright © 2010-2012, Niklas Laxström 12 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 13 * or later 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2 of the License, or 18 * (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License along 26 * with this program; if not, write to the Free Software Foundation, Inc., 27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 28 * http://www.gnu.org/copyleft/gpl.html 29 * 30 * 31 * @file 32 * @since 1.20 33 */ 34 class CLDRPluralRuleEvaluator { 35 /** 36 * Evaluate a number against a set of plural rules. If a rule passes, 37 * return the index of plural rule. 38 * 39 * @param int $number The number to be evaluated against the rules 40 * @param array $rules The associative array of plural rules in pluralform => rule format. 41 * @return int The index of the plural form which passed the evaluation 42 */ 43 public static function evaluate( $number, array $rules ) { 44 $rules = self::compile( $rules ); 45 46 return self::evaluateCompiled( $number, $rules ); 47 } 48 49 /** 50 * Convert a set of rules to a compiled form which is optimised for 51 * fast evaluation. The result will be an array of strings, and may be cached. 52 * 53 * @param array $rules The rules to compile 54 * @return array An array of compile rules. 55 */ 56 public static function compile( array $rules ) { 57 // We can't use array_map() for this because it generates a warning if 58 // there is an exception. 59 foreach ( $rules as &$rule ) { 60 $rule = CLDRPluralRuleConverter::convert( $rule ); 61 } 62 63 return $rules; 64 } 65 66 /** 67 * Evaluate a compiled set of rules returned by compile(). Do not allow 68 * the user to edit the compiled form, or else PHP errors may result. 69 * 70 * @param string $number The number to be evaluated against the rules, in English, or it 71 * may be a type convertible to string. 72 * @param array $rules The associative array of plural rules in pluralform => rule format. 73 * @return int The index of the plural form which passed the evaluation 74 */ 75 public static function evaluateCompiled( $number, array $rules ) { 76 // Calculate the values of the operand symbols 77 $number = strval( $number ); 78 if ( !preg_match( '/^ -? ( ([0-9]+) (?: \. ([0-9]+) )? )$/x', $number, $m ) ) { 79 wfDebug( __METHOD__ . ": invalid number input, returning 'other'\n" ); 80 81 return count( $rules ); 82 } 83 if ( !isset( $m[3] ) ) { 84 $operandSymbols = array( 85 'n' => intval( $m[1] ), 86 'i' => intval( $m[1] ), 87 'v' => 0, 88 'w' => 0, 89 'f' => 0, 90 't' => 0 91 ); 92 } else { 93 $absValStr = $m[1]; 94 $intStr = $m[2]; 95 $fracStr = $m[3]; 96 $operandSymbols = array( 97 'n' => floatval( $absValStr ), 98 'i' => intval( $intStr ), 99 'v' => strlen( $fracStr ), 100 'w' => strlen( rtrim( $fracStr, '0' ) ), 101 'f' => intval( $fracStr ), 102 't' => intval( rtrim( $fracStr, '0' ) ), 103 ); 104 } 105 106 // The compiled form is RPN, with tokens strictly delimited by 107 // spaces, so this is a simple RPN evaluator. 108 foreach ( $rules as $i => $rule ) { 109 $stack = array(); 110 $zero = ord( '0' ); 111 $nine = ord( '9' ); 112 foreach ( StringUtils::explode( ' ', $rule ) as $token ) { 113 $ord = ord( $token ); 114 if ( isset( $operandSymbols[$token] ) ) { 115 $stack[] = $operandSymbols[$token]; 116 } elseif ( $ord >= $zero && $ord <= $nine ) { 117 $stack[] = intval( $token ); 118 } else { 119 $right = array_pop( $stack ); 120 $left = array_pop( $stack ); 121 $result = self::doOperation( $token, $left, $right ); 122 $stack[] = $result; 123 } 124 } 125 if ( $stack[0] ) { 126 return $i; 127 } 128 } 129 // None of the provided rules match. The number belongs to category 130 // 'other', which comes last. 131 return count( $rules ); 132 } 133 134 /** 135 * Do a single operation 136 * 137 * @param string $token The token string 138 * @param mixed $left The left operand. If it is an object, its state may be destroyed. 139 * @param mixed $right The right operand 140 * @throws CLDRPluralRuleError 141 * @return mixed The operation result 142 */ 143 private static function doOperation( $token, $left, $right ) { 144 if ( in_array( $token, array( 'in', 'not-in', 'within', 'not-within' ) ) ) { 145 if ( !( $right instanceof CLDRPluralRuleEvaluatorRange ) ) { 146 $right = new CLDRPluralRuleEvaluatorRange( $right ); 147 } 148 } 149 switch ( $token ) { 150 case 'or': 151 return $left || $right; 152 case 'and': 153 return $left && $right; 154 case 'is': 155 return $left == $right; 156 case 'is-not': 157 return $left != $right; 158 case 'in': 159 return $right->isNumberIn( $left ); 160 case 'not-in': 161 return !$right->isNumberIn( $left ); 162 case 'within': 163 return $right->isNumberWithin( $left ); 164 case 'not-within': 165 return !$right->isNumberWithin( $left ); 166 case 'mod': 167 if ( is_int( $left ) ) { 168 return (int)fmod( $left, $right ); 169 } 170 171 return fmod( $left, $right ); 172 case ',': 173 if ( $left instanceof CLDRPluralRuleEvaluatorRange ) { 174 $range = $left; 175 } else { 176 $range = new CLDRPluralRuleEvaluatorRange( $left ); 177 } 178 $range->add( $right ); 179 180 return $range; 181 case '..': 182 return new CLDRPluralRuleEvaluatorRange( $left, $right ); 183 default: 184 throw new CLDRPluralRuleError( "Invalid RPN token" ); 185 } 186 } 187 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |