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

Parser.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 7.95 KiB


001  <?php
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\Plugins\FancyPants;
009   
010  use s9e\TextFormatter\Plugins\ParserBase;
011   
012  class Parser extends ParserBase
013  {
014      /**
015      * @var bool Whether currrent test contains a double quote character
016      */
017      protected $hasDoubleQuote;
018   
019      /**
020      * @var bool Whether currrent test contains a single quote character
021      */
022      protected $hasSingleQuote;
023   
024      /**
025      * @var string Text being parsed
026      */
027      protected $text;
028   
029      /**
030      * {@inheritdoc}
031      */
032      public function parse($text, array $matches)
033      {
034          $this->text           = $text;
035          $this->hasSingleQuote = (strpos($text, "'") !== false);
036          $this->hasDoubleQuote = (strpos($text, '"') !== false);
037   
038          if (empty($this->config['disableQuotes']))
039          {
040              $this->parseSingleQuotes();
041              $this->parseSingleQuotePairs();
042              $this->parseDoubleQuotePairs();
043          }
044          if (empty($this->config['disableGuillemets']))
045          {
046              $this->parseGuillemets();
047          }
048          if (empty($this->config['disableMathSymbols']))
049          {
050              $this->parseNotEqualSign();
051              $this->parseSymbolsAfterDigits();
052              $this->parseFractions();
053          }
054          if (empty($this->config['disablePunctuation']))
055          {
056              $this->parseDashesAndEllipses();
057          }
058          if (empty($this->config['disableSymbols']))
059          {
060              $this->parseSymbolsInParentheses();
061          }
062   
063          unset($this->text);
064      }
065   
066      /**
067      * Add a fancy replacement tag
068      *
069      * @param  integer $tagPos Position of the tag in the text
070      * @param  integer $tagLen Length of text consumed by the tag
071      * @param  string  $chr    Replacement character
072      * @param  integer $prio   Tag's priority
073      * @return \s9e\TextFormatter\Parser\Tag
074      */
075      protected function addTag($tagPos, $tagLen, $chr, $prio = 0)
076      {
077          $tag = $this->parser->addSelfClosingTag($this->config['tagName'], $tagPos, $tagLen, $prio);
078          $tag->setAttribute($this->config['attrName'], $chr);
079   
080          return $tag;
081      }
082   
083      /**
084      * Parse dashes and ellipses
085      *
086      * Does en dash –, em dash — and ellipsis …
087      *
088      * @return void
089      */
090      protected function parseDashesAndEllipses()
091      {
092          if (strpos($this->text, '...') === false && strpos($this->text, '--') === false)
093          {
094              return;
095          }
096   
097          $chrs = [
098              '--'  => "\xE2\x80\x93",
099              '---' => "\xE2\x80\x94",
100              '...' => "\xE2\x80\xA6"
101          ];
102          $regexp = '/---?|\\.\\.\\./S';
103          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
104          foreach ($matches[0] as $m)
105          {
106              $this->addTag($m[1], strlen($m[0]), $chrs[$m[0]]);
107          }
108      }
109   
110      /**
111      * Parse pairs of double quotes
112      *
113      * Does quote pairs “” -- must be done separately to handle nesting
114      *
115      * @return void
116      */
117      protected function parseDoubleQuotePairs()
118      {
119          if ($this->hasDoubleQuote)
120          {
121              $this->parseQuotePairs(
122                  '/(?<![0-9\\pL])"[^"\\n]+"(?![0-9\\pL])/uS',
123                  "\xE2\x80\x9C",
124                  "\xE2\x80\x9D"
125              );
126          }
127      }
128   
129      /**
130      * Parse vulgar fractions
131      *
132      * @return void
133      */
134      protected function parseFractions()
135      {
136          if (strpos($this->text, '/') === false)
137          {
138              return;
139          }
140   
141          $map = [
142              '1/4'  => "\xC2\xBC",
143              '1/2'  => "\xC2\xBD",
144              '3/4'  => "\xC2\xBE",
145              '1/7'  => "\xE2\x85\x90",
146              '1/9'  => "\xE2\x85\x91",
147              '1/10' => "\xE2\x85\x92",
148              '1/3'  => "\xE2\x85\x93",
149              '2/3'  => "\xE2\x85\x94",
150              '1/5'  => "\xE2\x85\x95",
151              '2/5'  => "\xE2\x85\x96",
152              '3/5'  => "\xE2\x85\x97",
153              '4/5'  => "\xE2\x85\x98",
154              '1/6'  => "\xE2\x85\x99",
155              '5/6'  => "\xE2\x85\x9A",
156              '1/8'  => "\xE2\x85\x9B",
157              '3/8'  => "\xE2\x85\x9C",
158              '5/8'  => "\xE2\x85\x9D",
159              '7/8'  => "\xE2\x85\x9E",
160              '0/3'  => "\xE2\x86\x89"
161          ];
162   
163          $regexp = '/\\b(?:0\\/3|1\\/(?:[2-9]|10)|2\\/[35]|3\\/[458]|4\\/5|5\\/[68]|7\\/8)\\b/S';
164          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
165          foreach ($matches[0] as $m)
166          {
167              $this->addTag($m[1], strlen($m[0]), $map[$m[0]]);
168          }
169      }
170   
171      /**
172      * Parse guillemets-style quotation marks
173      *
174      * @return void
175      */
176      protected function parseGuillemets()
177      {
178          if (strpos($this->text, '<<') === false)
179          {
180              return;
181          }
182   
183          $regexp = '/<<( ?)(?! )[^\\n<>]*?[^\\n <>]\\1>>(?!>)/';
184          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
185          foreach ($matches[0] as $m)
186          {
187              $left  = $this->addTag($m[1],                     2, "\xC2\xAB");
188              $right = $this->addTag($m[1] + strlen($m[0]) - 2, 2, "\xC2\xBB");
189   
190              $left->cascadeInvalidationTo($right);
191          }
192      }
193   
194      /**
195      * Parse the not equal sign
196      *
197      * Supports != and =/=
198      *
199      * @return void
200      */
201      protected function parseNotEqualSign()
202      {
203          if (strpos($this->text, '!=') === false && strpos($this->text, '=/=') === false)
204          {
205              return;
206          }
207   
208          $regexp = '/\\b (?:!|=\\/)=(?= \\b)/';
209          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
210          foreach ($matches[0] as $m)
211          {
212              $this->addTag($m[1] + 1, strlen($m[0]) - 1, "\xE2\x89\xA0");
213          }
214      }
215   
216      /**
217      * Parse pairs of quotes
218      *
219      * @param  string $regexp     Regexp used to identify quote pairs
220      * @param  string $leftQuote  Fancy replacement for left quote
221      * @param  string $rightQuote Fancy replacement for right quote
222      * @return void
223      */
224      protected function parseQuotePairs($regexp, $leftQuote, $rightQuote)
225      {
226          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
227          foreach ($matches[0] as $m)
228          {
229              $left  = $this->addTag($m[1], 1, $leftQuote);
230              $right = $this->addTag($m[1] + strlen($m[0]) - 1, 1, $rightQuote);
231   
232              // Cascade left tag's invalidation to the right so that if we skip the left quote,
233              // the right quote remains untouched
234              $left->cascadeInvalidationTo($right);
235          }
236      }
237   
238      /**
239      * Parse pairs of single quotes
240      *
241      * Does quote pairs ‘’ must be done separately to handle nesting
242      *
243      * @return void
244      */
245      protected function parseSingleQuotePairs()
246      {
247          if ($this->hasSingleQuote)
248          {
249              $this->parseQuotePairs(
250                  "/(?<![0-9\\pL])'[^'\\n]+'(?![0-9\\pL])/uS",
251                  "\xE2\x80\x98",
252                  "\xE2\x80\x99"
253              );
254          }
255      }
256   
257      /**
258      * Parse single quotes in general
259      *
260      * Does apostrophes ’ after a letter or at the beginning of a word or a couple of digits
261      *
262      * @return void
263      */
264      protected function parseSingleQuotes()
265      {
266          if (!$this->hasSingleQuote)
267          {
268              return;
269          }
270   
271          $regexp = "/(?<=\\pL)'|(?<!\\S)'(?=\\pL|[0-9]{2})/uS";
272          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
273          foreach ($matches[0] as $m)
274          {
275              // Give this tag a worse priority than default so that quote pairs take precedence
276              $this->addTag($m[1], 1, "\xE2\x80\x99", 10);
277          }
278      }
279   
280      /**
281      * Parse symbols found after digits
282      *
283      * Does symbols found after a digit:
284      *  - apostrophe ’ if it's followed by an "s" as in 80's
285      *  - prime ′ and double prime ″
286      *  - multiply sign × if it's followed by an optional space and another digit
287      *
288      * @return void
289      */
290      protected function parseSymbolsAfterDigits()
291      {
292          if (!$this->hasSingleQuote && !$this->hasDoubleQuote && strpos($this->text, 'x') === false)
293          {
294              return;
295          }
296   
297          $map = [
298              // 80's -- use an apostrophe
299              "'s" => "\xE2\x80\x99",
300              // 12' or 12" -- use a prime
301              "'"  => "\xE2\x80\xB2",
302              "' " => "\xE2\x80\xB2",
303              "'x" => "\xE2\x80\xB2",
304              '"'  => "\xE2\x80\xB3",
305              '" ' => "\xE2\x80\xB3",
306              '"x' => "\xE2\x80\xB3"
307          ];
308   
309          $regexp = "/[0-9](?>'s|[\"']? ?x(?= ?[0-9])|[\"'])/S";
310          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
311          foreach ($matches[0] as $m)
312          {
313              // Test for a multiply sign at the end
314              if (substr($m[0], -1) === 'x')
315              {
316                  $this->addTag($m[1] + strlen($m[0]) - 1, 1, "\xC3\x97");
317              }
318   
319              // Test for an apostrophe/prime right after the digit
320              $str = substr($m[0], 1, 2);
321              if (isset($map[$str]))
322              {
323                  $this->addTag($m[1] + 1, 1, $map[$str]);
324              }
325          }
326      }
327   
328      /**
329      * Parse symbols found in parentheses such as (c)
330      *
331      * Does symbols ©, ® and ™
332      *
333      * @return void
334      */
335      protected function parseSymbolsInParentheses()
336      {
337          if (strpos($this->text, '(') === false)
338          {
339              return;
340          }
341   
342          $chrs = [
343              '(c)'  => "\xC2\xA9",
344              '(r)'  => "\xC2\xAE",
345              '(tm)' => "\xE2\x84\xA2"
346          ];
347          $regexp = '/\\((?>c|r|tm)\\)/i';
348          preg_match_all($regexp, $this->text, $matches, PREG_OFFSET_CAPTURE);
349          foreach ($matches[0] as $m)
350          {
351              $this->addTag($m[1], strlen($m[0]), $chrs[strtr($m[0], 'CMRT', 'cmrt')]);
352          }
353      }
354  }