53 $this->names = $names;
54 $this->factory = $factory ?: MediaWikiServices::getInstance()->getMagicWordFactory();
62 public function add( $name ) {
63 $this->names[] = $name;
64 $this->hash = $this->baseRegex = $this->regex =
null;
73 $this->names = array_merge( $this->names, array_values( $names ) );
74 $this->hash = $this->baseRegex = $this->regex =
null;
82 if ( $this->hash ===
null ) {
83 $this->hash = [ 0 => [], 1 => [] ];
84 foreach ( $this->names as $name ) {
85 $magic = $this->factory->get( $name );
86 $case = intval( $magic->isCaseSensitive() );
87 foreach ( $magic->getSynonyms() as $syn ) {
89 $syn = $this->factory->getContentLanguage()->lc( $syn );
91 $this->hash[$case][$syn] = $name;
108 public function getBaseRegex(
bool $capture =
true,
string $delimiter =
'/' ): array {
109 if ( $capture && $delimiter ===
'/' && $this->baseRegex !== null ) {
110 return $this->baseRegex;
112 $regex = [ 0 => [], 1 => [] ];
114 foreach ( $this->names as $name ) {
115 $magic = $this->factory->get( $name );
116 $case = $magic->isCaseSensitive() ? 1 : 0;
117 foreach ( $magic->getSynonyms() as $i => $syn ) {
120 $it = strtr( $i,
'0123456789',
'abcdefghij' );
121 $groupName = $it .
'_' . $name;
122 $group =
'(?P<' . $groupName .
'>' . preg_quote( $syn, $delimiter ) .
')';
124 if ( isset( $allGroups[$groupName] ) ) {
126 __METHOD__ .
': duplicate internal name in magic word array: ' . $name
129 $allGroups[$groupName] =
true;
130 $regex[$case][] = $group;
132 $regex[$case][] = preg_quote( $syn, $delimiter );
136 '@phan-var array<int,string[]> $regex';
137 foreach ( $regex as $case => &$re ) {
138 $re = count( $re ) ? implode(
'|', $re ) :
'(?!)';
143 '@phan-var array<int,string> $regex';
145 if ( $capture && $delimiter ===
'/' ) {
146 $this->baseRegex = $regex;
157 if ( $this->regex ===
null ) {
159 $base = $this->getBaseRegex(
true,
'/' );
160 foreach (
$base as $case => $re ) {
161 $this->regex[$case] =
"/{$re}/S";
165 $this->regex[0] .=
'u';
178 return str_replace(
"\\$1",
"(.*?)", $this->getRegex() );
189 $base = $this->getBaseRegex(
true,
'/' );
190 foreach (
$base as $case => $re ) {
191 $newRegex[$case] =
"/^(?:{$re})/S";
207 $base = $this->getBaseRegex(
true,
'/' );
208 foreach (
$base as $case => $re ) {
209 $newRegex[$case] = str_replace(
"\\$1",
"(.*?)",
"/^(?:{$re})$/S" );
237 while ( ( $key = key( $m ) ) !==
null ) {
238 $value = current( $m );
240 if ( $key === 0 || $value ===
'' ) {
243 $parts = explode(
'_', $key, 2 );
244 if ( count( $parts ) != 2 ) {
247 throw new MWException( __METHOD__ .
': bad parameter name' );
249 list( , $magicName ) = $parts;
250 $paramValue = next( $m );
251 return [ $magicName, $paramValue ];
254 throw new MWException( __METHOD__ .
': parameter not found' );
268 $regexes = $this->getVariableStartToEndRegex();
269 foreach ( $regexes as $regex ) {
271 if ( preg_match( $regex, $text, $m ) ) {
272 return $this->parseMatch( $m );
275 return [
false, false ];
287 $hash = $this->getHash();
288 if ( isset( $hash[1][$text] ) ) {
289 return $hash[1][$text];
291 $lc = $this->factory->getContentLanguage()->lc( $text );
292 return $hash[0][$lc] ??
false;
305 $regexes = $this->getRegex();
306 foreach ( $regexes as $regex ) {
308 $res = preg_match_all( $regex, $text,
$matches, PREG_SET_ORDER );
309 if (
$res ===
false ) {
310 $error = preg_last_error();
312 $errorText = function_exists(
'preg_last_error_msg' ) ? preg_last_error_msg() :
'';
313 LoggerFactory::getInstance(
'parser' )->warning(
'preg_match_all error: {code} {errorText}', [
317 'errorText' => $errorText
319 throw new Exception(
"preg_match_all error $error: $errorText" );
322 list( $name, $param ) = $this->parseMatch( $m );
323 $found[$name] = $param;
326 $res = preg_replace( $regex,
'', $text );
327 if (
$res ===
null ) {
328 $error = preg_last_error();
330 $errorText = function_exists(
'preg_last_error_msg' ) ? preg_last_error_msg() :
'';
331 LoggerFactory::getInstance(
'parser' )->warning(
'preg_replace error: {code} {errorText}', [
335 'errorText' => $errorText
337 throw new Exception(
"preg_replace error $error: $errorText" );
355 $regexes = $this->getRegexStart();
356 foreach ( $regexes as $regex ) {
357 if ( preg_match( $regex, $text, $m ) ) {
358 list( $id, ) = $this->parseMatch( $m );
359 if ( strlen( $m[0] ) >= strlen( $text ) ) {
362 $text = substr( $text, strlen( $m[0] ) );
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Class for handling an array of magic words.
getBaseRegex(bool $capture=true, string $delimiter='/')
Get the base regex.
matchVariableStartToEnd( $text)
Match some text, with parameter capture Returns an array with the magic word name in the first elemen...
add( $name)
Add a magic word by name.
getVariableRegex()
Get a regex for matching variables with parameters.
__construct( $names=[], MagicWordFactory $factory=null)
parseMatch( $m)
Parse a match array from preg_match Returns array(magic word ID, parameter value) If there is no para...
matchStartToEnd( $text)
Match some text, without parameter capture Returns the magic word name, or false if there was no capt...
getRegexStart()
Get a regex anchored to the start of the string that does not match parameters.
matchStartAndRemove(&$text)
Return the ID of the magic word at the start of $text, and remove the prefix from $text.
getRegex()
Get an unanchored regex that does not match parameters.
getVariableStartToEndRegex()
Get an anchored regex for matching variables with parameters.
getHash()
Get a 2-d hashtable for this array.
matchAndRemove(&$text)
Returns an associative array, ID => param value, for all items that match Removes the matched items f...
addArray( $names)
Add a number of magic words by name.
A factory that stores information about MagicWords, and creates them on demand with caching.