[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php declare(strict_types=1); 2 3 /** 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2022 The s9e authors 6 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 7 */ 8 namespace s9e\TextFormatter\Configurator; 9 10 use RuntimeException; 11 use s9e\TextFormatter\Configurator\RecursiveParser\MatcherInterface; 12 13 class RecursiveParser 14 { 15 /** 16 * @var array Callback associated with each match name 17 */ 18 protected $callbacks = []; 19 20 /** 21 * @var array Match names associated with each group 22 */ 23 protected $groupMatches = []; 24 25 /** 26 * @var array Groups associated with each match name 27 */ 28 protected $matchGroups = []; 29 30 /** 31 * @var string Regexp used to match input 32 */ 33 protected $regexp; 34 35 /** 36 * Parse given string 37 * 38 * @param string $str 39 * @param string $name Allowed match, either match name or group name (default: allow all) 40 * @return mixed 41 */ 42 public function parse(string $str, string $name = '') 43 { 44 $regexp = $this->regexp; 45 if ($name !== '') 46 { 47 $restrict = (isset($this->groupMatches[$name])) ? implode('|', $this->groupMatches[$name]) : $name; 48 $regexp = preg_replace('(\\(\\?<(?!(?:' . $restrict . '|\\w+\\d+)>))', '(*F)$0', $regexp); 49 } 50 51 preg_match($regexp, $str, $m); 52 if (!isset($m['MARK'])) 53 { 54 throw new RuntimeException('Cannot parse ' . var_export($str, true)); 55 } 56 57 $name = $m['MARK']; 58 $args = $this->getArguments($m, $name); 59 60 return [ 61 'groups' => $this->matchGroups[$name] ?? [], 62 'match' => $name, 63 'value' => call_user_func_array($this->callbacks[$name], $args) 64 ]; 65 } 66 67 /** 68 * Set the list of matchers used by this parser 69 * 70 * @param MatcherInterface[] 71 * @return void 72 */ 73 public function setMatchers(array $matchers): void 74 { 75 $matchRegexps = []; 76 $this->groupMatches = []; 77 $this->matchGroups = []; 78 foreach ($this->getMatchersConfig($matchers) as $matchName => $matchConfig) 79 { 80 foreach ($matchConfig['groups'] as $group) 81 { 82 $this->groupMatches[$group][] = $matchName; 83 } 84 85 $regexp = $matchConfig['regexp']; 86 $regexp = $this->insertCaptureNames($matchName , $regexp); 87 $regexp = str_replace(' ', '\\s*+', $regexp); 88 $regexp = '(?<' . $matchName . '>' . $regexp . ')(*:' . $matchName . ')'; 89 90 $matchRegexps[] = $regexp; 91 $this->callbacks[$matchName] = $matchConfig['callback']; 92 $this->matchGroups[$matchName] = $matchConfig['groups']; 93 } 94 95 $groupRegexps = []; 96 foreach ($this->groupMatches as $group => $names) 97 { 98 $groupRegexps[] = '(?<' . $group . '>(?&' . implode(')|(?&', $names) . '))'; 99 } 100 101 $this->regexp = '((?(DEFINE)' . implode('', $groupRegexps). ')' 102 . '^(?:' . implode('|', $matchRegexps) . ')$)s'; 103 } 104 105 /** 106 * Get the list of arguments produced by a regexp's match 107 * 108 * @param string[] $matches Regexp matches 109 * @param string $name Regexp name 110 * @return string[] 111 */ 112 protected function getArguments(array $matches, string $name): array 113 { 114 $args = []; 115 $i = 0; 116 while (isset($matches[$name . $i])) 117 { 118 $args[] = $matches[$name . $i]; 119 ++$i; 120 } 121 122 return $args; 123 } 124 125 /** 126 * Collect, normalize, sort and return the config for all matchers 127 * 128 * @param MatcherInterface[] $matchers 129 * @return array 130 */ 131 protected function getMatchersConfig(array $matchers): array 132 { 133 $matchersConfig = []; 134 foreach ($matchers as $matcher) 135 { 136 foreach ($matcher->getMatchers() as $matchName => $matchConfig) 137 { 138 if (is_string($matchConfig)) 139 { 140 $matchConfig = ['regexp' => $matchConfig]; 141 } 142 $parts = explode(':', $matchName); 143 $matchName = array_pop($parts); 144 $matchConfig += [ 145 'callback' => [$matcher, 'parse' . $matchName], 146 'groups' => [], 147 'order' => 0 148 ]; 149 $matchConfig['name'] = $matchName; 150 $matchConfig['groups'] = array_unique(array_merge($matchConfig['groups'], $parts)); 151 sort($matchConfig['groups']); 152 153 $matchersConfig[$matchName] = $matchConfig; 154 } 155 } 156 uasort($matchersConfig, 'static::sortMatcherConfig'); 157 158 return $matchersConfig; 159 } 160 161 /** 162 * Insert capture names into given regexp 163 * 164 * @param string $name Name of the regexp, used to name captures 165 * @param string $regexp Original regexp 166 * @return string Modified regexp 167 */ 168 protected function insertCaptureNames(string $name, string $regexp): string 169 { 170 $i = 0; 171 172 return preg_replace_callback( 173 '((?<!\\\\)\\((?!\\?))', 174 function ($m) use (&$i, $name) 175 { 176 return '(?<' . $name . $i++ . '>'; 177 }, 178 $regexp 179 ); 180 } 181 182 /** 183 * Compare two matchers' config 184 * 185 * @param array $a 186 * @param array $b 187 * @return integer 188 */ 189 protected static function sortMatcherConfig(array $a, array $b): int 190 { 191 if ($a['order'] !== $b['order']) 192 { 193 return $a['order'] - $b['order']; 194 } 195 196 return strcmp($a['name'], $b['name']); 197 } 198 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |