From: addshore Date: Tue, 1 Mar 2016 10:49:29 +0000 (+0000) Subject: Move MagicWordArray class to own file X-Git-Tag: 1.31.0-rc.0~7777^2 X-Git-Url: http://git.cyclocoop.org/%22%20.%20generer_url_ecrire%28%22brouteur%22%2C%28%24id_rubrique%20?a=commitdiff_plain;h=26cd337c2e7fa0b9e5cbcdc69d8680ecd1ab8eb8;p=lhc%2Fweb%2Fwiklou.git Move MagicWordArray class to own file Change-Id: I9ba602da77f1c8d4270d8ae10d03e82a3197e5b1 --- diff --git a/autoload.php b/autoload.php index 5ec6218f28..e882547a78 100644 --- a/autoload.php +++ b/autoload.php @@ -756,7 +756,7 @@ $wgAutoloadLocalClasses = [ 'MWUnknownContentModelException' => __DIR__ . '/includes/content/ContentHandler.php', 'MachineReadableRCFeedFormatter' => __DIR__ . '/includes/rcfeed/MachineReadableRCFeedFormatter.php', 'MagicWord' => __DIR__ . '/includes/MagicWord.php', - 'MagicWordArray' => __DIR__ . '/includes/MagicWord.php', + 'MagicWordArray' => __DIR__ . '/includes/MagicWordArray.php', 'MailAddress' => __DIR__ . '/includes/mail/MailAddress.php', 'Maintenance' => __DIR__ . '/maintenance/Maintenance.php', 'MaintenanceFormatInstallDoc' => __DIR__ . '/maintenance/formatInstallDoc.php', diff --git a/includes/MagicWord.php b/includes/MagicWord.php index 12a445bc48..9ba43111c7 100644 --- a/includes/MagicWord.php +++ b/includes/MagicWord.php @@ -1,7 +1,5 @@ mId; } } - -/** - * Class for handling an array of magic words - * @ingroup Parser - */ -class MagicWordArray { - /** @var array */ - public $names = []; - - /** @var array */ - private $hash; - - private $baseRegex; - - private $regex; - - /** - * @param array $names - */ - function __construct( $names = [] ) { - $this->names = $names; - } - - /** - * Add a magic word by name - * - * @param string $name - */ - public function add( $name ) { - $this->names[] = $name; - $this->hash = $this->baseRegex = $this->regex = null; - } - - /** - * Add a number of magic words by name - * - * @param array $names - */ - public function addArray( $names ) { - $this->names = array_merge( $this->names, array_values( $names ) ); - $this->hash = $this->baseRegex = $this->regex = null; - } - - /** - * Get a 2-d hashtable for this array - * @return array - */ - function getHash() { - if ( is_null( $this->hash ) ) { - global $wgContLang; - $this->hash = [ 0 => [], 1 => [] ]; - foreach ( $this->names as $name ) { - $magic = MagicWord::get( $name ); - $case = intval( $magic->isCaseSensitive() ); - foreach ( $magic->getSynonyms() as $syn ) { - if ( !$case ) { - $syn = $wgContLang->lc( $syn ); - } - $this->hash[$case][$syn] = $name; - } - } - } - return $this->hash; - } - - /** - * Get the base regex - * @return array - */ - function getBaseRegex() { - if ( is_null( $this->baseRegex ) ) { - $this->baseRegex = [ 0 => '', 1 => '' ]; - foreach ( $this->names as $name ) { - $magic = MagicWord::get( $name ); - $case = intval( $magic->isCaseSensitive() ); - foreach ( $magic->getSynonyms() as $i => $syn ) { - // Group name must start with a non-digit in PCRE 8.34+ - $it = strtr( $i, '0123456789', 'abcdefghij' ); - $group = "(?P<{$it}_{$name}>" . preg_quote( $syn, '/' ) . ')'; - if ( $this->baseRegex[$case] === '' ) { - $this->baseRegex[$case] = $group; - } else { - $this->baseRegex[$case] .= '|' . $group; - } - } - } - } - return $this->baseRegex; - } - - /** - * Get an unanchored regex that does not match parameters - * @return array - */ - function getRegex() { - if ( is_null( $this->regex ) ) { - $base = $this->getBaseRegex(); - $this->regex = [ '', '' ]; - if ( $this->baseRegex[0] !== '' ) { - $this->regex[0] = "/{$base[0]}/iuS"; - } - if ( $this->baseRegex[1] !== '' ) { - $this->regex[1] = "/{$base[1]}/S"; - } - } - return $this->regex; - } - - /** - * Get a regex for matching variables with parameters - * - * @return string - */ - function getVariableRegex() { - return str_replace( "\\$1", "(.*?)", $this->getRegex() ); - } - - /** - * Get a regex anchored to the start of the string that does not match parameters - * - * @return array - */ - function getRegexStart() { - $base = $this->getBaseRegex(); - $newRegex = [ '', '' ]; - if ( $base[0] !== '' ) { - $newRegex[0] = "/^(?:{$base[0]})/iuS"; - } - if ( $base[1] !== '' ) { - $newRegex[1] = "/^(?:{$base[1]})/S"; - } - return $newRegex; - } - - /** - * Get an anchored regex for matching variables with parameters - * - * @return array - */ - function getVariableStartToEndRegex() { - $base = $this->getBaseRegex(); - $newRegex = [ '', '' ]; - if ( $base[0] !== '' ) { - $newRegex[0] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[0]})$/iuS" ); - } - if ( $base[1] !== '' ) { - $newRegex[1] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[1]})$/S" ); - } - return $newRegex; - } - - /** - * @since 1.20 - * @return array - */ - public function getNames() { - return $this->names; - } - - /** - * Parse a match array from preg_match - * Returns array(magic word ID, parameter value) - * If there is no parameter value, that element will be false. - * - * @param array $m - * - * @throws MWException - * @return array - */ - function parseMatch( $m ) { - reset( $m ); - while ( list( $key, $value ) = each( $m ) ) { - if ( $key === 0 || $value === '' ) { - continue; - } - $parts = explode( '_', $key, 2 ); - if ( count( $parts ) != 2 ) { - // This shouldn't happen - // continue; - throw new MWException( __METHOD__ . ': bad parameter name' ); - } - list( /* $synIndex */, $magicName ) = $parts; - $paramValue = next( $m ); - return [ $magicName, $paramValue ]; - } - // This shouldn't happen either - throw new MWException( __METHOD__ . ': parameter not found' ); - } - - /** - * Match some text, with parameter capture - * Returns an array with the magic word name in the first element and the - * parameter in the second element. - * Both elements are false if there was no match. - * - * @param string $text - * - * @return array - */ - public function matchVariableStartToEnd( $text ) { - $regexes = $this->getVariableStartToEndRegex(); - foreach ( $regexes as $regex ) { - if ( $regex !== '' ) { - $m = []; - if ( preg_match( $regex, $text, $m ) ) { - return $this->parseMatch( $m ); - } - } - } - return [ false, false ]; - } - - /** - * Match some text, without parameter capture - * Returns the magic word name, or false if there was no capture - * - * @param string $text - * - * @return string|bool False on failure - */ - public function matchStartToEnd( $text ) { - $hash = $this->getHash(); - if ( isset( $hash[1][$text] ) ) { - return $hash[1][$text]; - } - global $wgContLang; - $lc = $wgContLang->lc( $text ); - if ( isset( $hash[0][$lc] ) ) { - return $hash[0][$lc]; - } - return false; - } - - /** - * Returns an associative array, ID => param value, for all items that match - * Removes the matched items from the input string (passed by reference) - * - * @param string $text - * - * @return array - */ - public function matchAndRemove( &$text ) { - $found = []; - $regexes = $this->getRegex(); - foreach ( $regexes as $regex ) { - if ( $regex === '' ) { - continue; - } - $matches = []; - $res = preg_match_all( $regex, $text, $matches, PREG_SET_ORDER ); - if ( $res === false ) { - LoggerFactory::getInstance( 'parser' )->warning( 'preg_match_all returned false', [ - 'code' => preg_last_error(), - 'regex' => $regex, - 'text' => $text, - ] ); - } elseif ( $res ) { - foreach ( $matches as $m ) { - list( $name, $param ) = $this->parseMatch( $m ); - $found[$name] = $param; - } - } - $res = preg_replace( $regex, '', $text ); - if ( $res === null ) { - LoggerFactory::getInstance( 'parser' )->warning( 'preg_replace returned null', [ - 'code' => preg_last_error(), - 'regex' => $regex, - 'text' => $text, - ] ); - } - $text = $res; - } - return $found; - } - - /** - * Return the ID of the magic word at the start of $text, and remove - * the prefix from $text. - * Return false if no match found and $text is not modified. - * Does not match parameters. - * - * @param string $text - * - * @return int|bool False on failure - */ - public function matchStartAndRemove( &$text ) { - $regexes = $this->getRegexStart(); - foreach ( $regexes as $regex ) { - if ( $regex === '' ) { - continue; - } - if ( preg_match( $regex, $text, $m ) ) { - list( $id, ) = $this->parseMatch( $m ); - if ( strlen( $m[0] ) >= strlen( $text ) ) { - $text = ''; - } else { - $text = substr( $text, strlen( $m[0] ) ); - } - return $id; - } - } - return false; - } -} diff --git a/includes/MagicWordArray.php b/includes/MagicWordArray.php new file mode 100644 index 0000000000..ee5de6b59f --- /dev/null +++ b/includes/MagicWordArray.php @@ -0,0 +1,329 @@ +names = $names; + } + + /** + * Add a magic word by name + * + * @param string $name + */ + public function add( $name ) { + $this->names[] = $name; + $this->hash = $this->baseRegex = $this->regex = null; + } + + /** + * Add a number of magic words by name + * + * @param array $names + */ + public function addArray( $names ) { + $this->names = array_merge( $this->names, array_values( $names ) ); + $this->hash = $this->baseRegex = $this->regex = null; + } + + /** + * Get a 2-d hashtable for this array + * @return array + */ + function getHash() { + if ( is_null( $this->hash ) ) { + global $wgContLang; + $this->hash = [ 0 => [], 1 => [] ]; + foreach ( $this->names as $name ) { + $magic = MagicWord::get( $name ); + $case = intval( $magic->isCaseSensitive() ); + foreach ( $magic->getSynonyms() as $syn ) { + if ( !$case ) { + $syn = $wgContLang->lc( $syn ); + } + $this->hash[$case][$syn] = $name; + } + } + } + return $this->hash; + } + + /** + * Get the base regex + * @return array + */ + function getBaseRegex() { + if ( is_null( $this->baseRegex ) ) { + $this->baseRegex = [ 0 => '', 1 => '' ]; + foreach ( $this->names as $name ) { + $magic = MagicWord::get( $name ); + $case = intval( $magic->isCaseSensitive() ); + foreach ( $magic->getSynonyms() as $i => $syn ) { + // Group name must start with a non-digit in PCRE 8.34+ + $it = strtr( $i, '0123456789', 'abcdefghij' ); + $group = "(?P<{$it}_{$name}>" . preg_quote( $syn, '/' ) . ')'; + if ( $this->baseRegex[$case] === '' ) { + $this->baseRegex[$case] = $group; + } else { + $this->baseRegex[$case] .= '|' . $group; + } + } + } + } + return $this->baseRegex; + } + + /** + * Get an unanchored regex that does not match parameters + * @return array + */ + function getRegex() { + if ( is_null( $this->regex ) ) { + $base = $this->getBaseRegex(); + $this->regex = [ '', '' ]; + if ( $this->baseRegex[0] !== '' ) { + $this->regex[0] = "/{$base[0]}/iuS"; + } + if ( $this->baseRegex[1] !== '' ) { + $this->regex[1] = "/{$base[1]}/S"; + } + } + return $this->regex; + } + + /** + * Get a regex for matching variables with parameters + * + * @return string + */ + function getVariableRegex() { + return str_replace( "\\$1", "(.*?)", $this->getRegex() ); + } + + /** + * Get a regex anchored to the start of the string that does not match parameters + * + * @return array + */ + function getRegexStart() { + $base = $this->getBaseRegex(); + $newRegex = [ '', '' ]; + if ( $base[0] !== '' ) { + $newRegex[0] = "/^(?:{$base[0]})/iuS"; + } + if ( $base[1] !== '' ) { + $newRegex[1] = "/^(?:{$base[1]})/S"; + } + return $newRegex; + } + + /** + * Get an anchored regex for matching variables with parameters + * + * @return array + */ + function getVariableStartToEndRegex() { + $base = $this->getBaseRegex(); + $newRegex = [ '', '' ]; + if ( $base[0] !== '' ) { + $newRegex[0] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[0]})$/iuS" ); + } + if ( $base[1] !== '' ) { + $newRegex[1] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[1]})$/S" ); + } + return $newRegex; + } + + /** + * @since 1.20 + * @return array + */ + public function getNames() { + return $this->names; + } + + /** + * Parse a match array from preg_match + * Returns array(magic word ID, parameter value) + * If there is no parameter value, that element will be false. + * + * @param array $m + * + * @throws MWException + * @return array + */ + function parseMatch( $m ) { + reset( $m ); + while ( list( $key, $value ) = each( $m ) ) { + if ( $key === 0 || $value === '' ) { + continue; + } + $parts = explode( '_', $key, 2 ); + if ( count( $parts ) != 2 ) { + // This shouldn't happen + // continue; + throw new MWException( __METHOD__ . ': bad parameter name' ); + } + list( /* $synIndex */, $magicName ) = $parts; + $paramValue = next( $m ); + return [ $magicName, $paramValue ]; + } + // This shouldn't happen either + throw new MWException( __METHOD__ . ': parameter not found' ); + } + + /** + * Match some text, with parameter capture + * Returns an array with the magic word name in the first element and the + * parameter in the second element. + * Both elements are false if there was no match. + * + * @param string $text + * + * @return array + */ + public function matchVariableStartToEnd( $text ) { + $regexes = $this->getVariableStartToEndRegex(); + foreach ( $regexes as $regex ) { + if ( $regex !== '' ) { + $m = []; + if ( preg_match( $regex, $text, $m ) ) { + return $this->parseMatch( $m ); + } + } + } + return [ false, false ]; + } + + /** + * Match some text, without parameter capture + * Returns the magic word name, or false if there was no capture + * + * @param string $text + * + * @return string|bool False on failure + */ + public function matchStartToEnd( $text ) { + $hash = $this->getHash(); + if ( isset( $hash[1][$text] ) ) { + return $hash[1][$text]; + } + global $wgContLang; + $lc = $wgContLang->lc( $text ); + if ( isset( $hash[0][$lc] ) ) { + return $hash[0][$lc]; + } + return false; + } + + /** + * Returns an associative array, ID => param value, for all items that match + * Removes the matched items from the input string (passed by reference) + * + * @param string $text + * + * @return array + */ + public function matchAndRemove( &$text ) { + $found = []; + $regexes = $this->getRegex(); + foreach ( $regexes as $regex ) { + if ( $regex === '' ) { + continue; + } + $matches = []; + $res = preg_match_all( $regex, $text, $matches, PREG_SET_ORDER ); + if ( $res === false ) { + LoggerFactory::getInstance( 'parser' )->warning( 'preg_match_all returned false', [ + 'code' => preg_last_error(), + 'regex' => $regex, + 'text' => $text, + ] ); + } elseif ( $res ) { + foreach ( $matches as $m ) { + list( $name, $param ) = $this->parseMatch( $m ); + $found[$name] = $param; + } + } + $res = preg_replace( $regex, '', $text ); + if ( $res === null ) { + LoggerFactory::getInstance( 'parser' )->warning( 'preg_replace returned null', [ + 'code' => preg_last_error(), + 'regex' => $regex, + 'text' => $text, + ] ); + } + $text = $res; + } + return $found; + } + + /** + * Return the ID of the magic word at the start of $text, and remove + * the prefix from $text. + * Return false if no match found and $text is not modified. + * Does not match parameters. + * + * @param string $text + * + * @return int|bool False on failure + */ + public function matchStartAndRemove( &$text ) { + $regexes = $this->getRegexStart(); + foreach ( $regexes as $regex ) { + if ( $regex === '' ) { + continue; + } + if ( preg_match( $regex, $text, $m ) ) { + list( $id, ) = $this->parseMatch( $m ); + if ( strlen( $m[0] ) >= strlen( $text ) ) { + $text = ''; + } else { + $text = substr( $text, strlen( $m[0] ) ); + } + return $id; + } + } + return false; + } +}