Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

RecursiveParser.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 4.67 KiB


001  <?php declare(strict_types=1);
002   
003  /**
004  * @package   s9e\TextFormatter
005  * @copyright Copyright (c) 2010-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\TextFormatter\Configurator;
009   
010  use RuntimeException;
011  use s9e\TextFormatter\Configurator\RecursiveParser\MatcherInterface;
012   
013  class RecursiveParser
014  {
015      /**
016      * @var array Callback associated with each match name
017      */
018      protected $callbacks = [];
019   
020      /**
021      * @var array Match names associated with each group
022      */
023      protected $groupMatches = [];
024   
025      /**
026      * @var array Groups associated with each match name
027      */
028      protected $matchGroups = [];
029   
030      /**
031      * @var string Regexp used to match input
032      */
033      protected $regexp;
034   
035      /**
036      * Parse given string
037      *
038      * @param  string $str
039      * @param  string $name Allowed match, either match name or group name (default: allow all)
040      * @return mixed
041      */
042      public function parse(string $str, string $name = '')
043      {
044          $regexp = $this->regexp;
045          if ($name !== '')
046          {
047              $restrict = (isset($this->groupMatches[$name])) ? implode('|', $this->groupMatches[$name]) : $name;
048              $regexp   = preg_replace('(\\(\\?<(?!(?:' . $restrict . '|\\w+\\d+)>))', '(*F)$0', $regexp);
049          }
050   
051          preg_match($regexp, $str, $m);
052          if (!isset($m['MARK']))
053          {
054              throw new RuntimeException('Cannot parse ' . var_export($str, true));
055          }
056   
057          $name = $m['MARK'];
058          $args = $this->getArguments($m, $name);
059   
060          return [
061              'groups' => $this->matchGroups[$name] ?? [],
062              'match'  => $name,
063              'value'  => call_user_func_array($this->callbacks[$name], $args)
064          ];
065      }
066   
067      /**
068      * Set the list of matchers used by this parser
069      *
070      * @param  MatcherInterface[]
071      * @return void
072      */
073      public function setMatchers(array $matchers): void
074      {
075          $matchRegexps       = [];
076          $this->groupMatches = [];
077          $this->matchGroups  = [];
078          foreach ($this->getMatchersConfig($matchers) as $matchName => $matchConfig)
079          {
080              foreach ($matchConfig['groups'] as $group)
081              {
082                  $this->groupMatches[$group][] = $matchName;
083              }
084   
085              $regexp = $matchConfig['regexp'];
086              $regexp = $this->insertCaptureNames($matchName , $regexp);
087              $regexp = str_replace(' ', '\\s*+', $regexp);
088              $regexp = '(?<' . $matchName  . '>' . $regexp . ')(*:' . $matchName  . ')';
089   
090              $matchRegexps[]                = $regexp;
091              $this->callbacks[$matchName]   = $matchConfig['callback'];
092              $this->matchGroups[$matchName] = $matchConfig['groups'];
093          }
094   
095          $groupRegexps = [];
096          foreach ($this->groupMatches as $group => $names)
097          {
098              $groupRegexps[] = '(?<' . $group . '>(?&' . implode(')|(?&', $names) . '))';
099          }
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  }