Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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

Utf8.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 22.83 KiB


001  <?php
002   
003  /*
004   * Copyright (C) 2016 Nicolas Grekas - p@tchwork.com
005   *
006   * This library is free software; you can redistribute it and/or modify it
007   * under the terms of the (at your option):
008   * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
009   * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
010   */
011   
012  namespace Patchwork;
013   
014  use Normalizer as n;
015   
016  /**
017   * UTF-8 Grapheme Cluster aware string manipulations implementing the quasi complete
018   * set of native PHP string functions that need UTF-8 awareness and more.
019   * Missing are printf-family functions.
020   */
021  class Utf8
022  {
023      protected static $pathPrefix;
024      protected static $commonCaseFold = array(
025          array('µ','ſ',"\xCD\x85",'ς',"\xCF\x90","\xCF\x91","\xCF\x95","\xCF\x96","\xCF\xB0","\xCF\xB1","\xCF\xB5","\xE1\xBA\x9B","\xE1\xBE\xBE"),
026          array('μ','s','ι',       'σ','β',       'θ',       'φ',       'π',       'κ',       'ρ',       'ε',       "\xE1\xB9\xA1",'ι'),
027      );
028      protected static $cp1252 = array('€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ');
029      protected static $utf8   = array('€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ');
030   
031      public static function isUtf8($s)
032      {
033          return (bool) preg_match('//u', $s); // Since PHP 5.2.5, this also excludes invalid five and six bytes sequences
034      }
035   
036      // Generic UTF-8 to ASCII transliteration
037   
038      public static function toAscii($s, $subst_chr = '?')
039      {
040          if (preg_match("/[\x80-\xFF]/", $s)) {
041              static $translitExtra = array();
042              $translitExtra or $translitExtra = static::getData('translit_extra');
043   
044              $s = n::normalize($s, n::NFKC);
045   
046              $glibc = 'glibc' === ICONV_IMPL;
047   
048              preg_match_all('/./u', $s, $s);
049   
050              foreach ($s[0] as &$c) {
051                  if (!isset($c[1])) {
052                      continue;
053                  }
054   
055                  if ($glibc) {
056                      $t = iconv('UTF-8', 'ASCII//TRANSLIT', $c);
057                  } else {
058                      $t = iconv('UTF-8', 'ASCII//IGNORE//TRANSLIT', $c);
059   
060                      if (!isset($t[0])) {
061                          $t = '?';
062                      } elseif (isset($t[1])) {
063                          $t = ltrim($t, '\'`"^~');
064                      }
065                  }
066   
067                  if ('?' === $t) {
068                      if (isset($translitExtra[$c])) {
069                          $t = $translitExtra[$c];
070                      } else {
071                          $t = n::normalize($c, n::NFD);
072   
073                          if ($t[0] < "\x80") {
074                              $t = $t[0];
075                          } else {
076                              $t = $subst_chr;
077                          }
078                      }
079                  }
080   
081                  $c = $t;
082              }
083   
084              $s = implode('', $s[0]);
085          }
086   
087          return $s;
088      }
089   
090      public static function wrapPath($path = '')
091      {
092          if (null === static::$pathPrefix) {
093              static $hasWfio;
094              isset($hasWfio) or $hasWfio = extension_loaded('wfio');
095   
096              if ($hasWfio) {
097                  static::$pathPrefix = 'wfio://';
098              } elseif ('\\' === DIRECTORY_SEPARATOR && class_exists('COM', false)) {
099                  static::$pathPrefix = 'utf8'.mt_rand();
100                  stream_wrapper_register(static::$pathPrefix, 'Patchwork\Utf8\WindowsStreamWrapper');
101                  static::$pathPrefix .= '://';
102              } else {
103                  if ('\\' === DIRECTORY_SEPARATOR) {
104                      trigger_error('The `wfio` or `com_dotnet` extension is required to handle UTF-8 filesystem access on Windows');
105                  }
106                  static::$pathPrefix = 'file://';
107              }
108          }
109   
110          return static::$pathPrefix.$path;
111      }
112   
113      public static function filter($var, $normalization_form = 4 /* n::NFC */, $leading_combining = '◌')
114      {
115          switch (gettype($var)) {
116              case 'array':
117                  foreach ($var as $k => $v) {
118                      $var[$k] = static::filter($v, $normalization_form, $leading_combining);
119                  }
120                  break;
121   
122              case 'object':
123                  foreach ($var as $k => $v) {
124                      $var->$k = static::filter($v, $normalization_form, $leading_combining);
125                  }
126                  break;
127   
128              case 'string':
129                  if (false !== strpos($var, "\r")) {
130                      // Workaround https://bugs.php.net/65732
131                      $var = str_replace("\r\n", "\n", $var);
132                      $var = strtr($var, "\r", "\n");
133                  }
134   
135                  if (preg_match('/[\x80-\xFF]/', $var)) {
136                      if (n::isNormalized($var, $normalization_form)) {
137                          $n = '-';
138                      } else {
139                          $n = n::normalize($var, $normalization_form);
140                          if (isset($n[0])) {
141                              $var = $n;
142                          } else {
143                              $var = static::utf8_encode($var);
144                          }
145                      }
146   
147                      if ($var[0] >= "\x80" && isset($n[0], $leading_combining[0]) && preg_match('/^\p{Mn}/u', $var)) {
148                          // Prevent leading combining chars
149                          // for NFC-safe concatenations.
150                          $var = $leading_combining.$var;
151                      }
152                  }
153                  break;
154          }
155   
156          return $var;
157      }
158   
159      // Unicode transformation for caseless matching
160      // see http://unicode.org/reports/tr21/tr21-5.html
161   
162      public static function strtocasefold($s, $full = true)
163      {
164          $s = str_replace(self::$commonCaseFold[0], self::$commonCaseFold[1], $s);
165   
166          if ($full) {
167              static $fullCaseFold = false;
168              $fullCaseFold or $fullCaseFold = static::getData('caseFolding_full');
169   
170              $s = str_replace($fullCaseFold[0], $fullCaseFold[1], $s);
171          }
172   
173          return static::strtolower($s);
174      }
175   
176      // Generic case sensitive collation support for self::strnatcmp()
177   
178      public static function strtonatfold($s)
179      {
180          $s = n::normalize($s, n::NFD);
181   
182          return preg_replace('/\p{Mn}+/u', '', $s);
183      }
184   
185      // PHP string functions that need UTF-8 awareness
186   
187      public static function filter_input($type, $var, $filter = FILTER_DEFAULT, $option = null)
188      {
189          if (4 > func_num_args()) {
190              $var = filter_input($type, $var, $filter);
191          } else {
192              $var = filter_input($type, $var, $filter, $option);
193          }
194   
195          return static::filter($var);
196      }
197   
198      public static function filter_input_array($type, $def = null, $add_empty = true)
199      {
200          if (2 > func_num_args()) {
201              $a = filter_input_array($type);
202          } else {
203              $a = filter_input_array($type, $def, $add_empty);
204          }
205   
206          return static::filter($a);
207      }
208   
209      public static function json_decode($json, $assoc = false, $depth = 512, $options = 0)
210      {
211          if (PHP_VERSION_ID < 50400) {
212              $json = json_decode($json, $assoc, $depth);
213          } else {
214              $json = json_decode($json, $assoc, $depth, $options);
215          }
216   
217          return static::filter($json);
218      }
219   
220      public static function substr($s, $start, $len = 2147483647)
221      {
222          static $bug62759;
223          isset($bug62759) or $bug62759 = extension_loaded('intl') && 'à' === @grapheme_substr('éà', 1, -2);
224   
225          if ($bug62759) {
226              return PHP\Shim\Intl::grapheme_substr_workaround62759($s, $start, $len);
227          } else {
228              return grapheme_substr($s, $start, $len);
229          }
230      }
231   
232      public static function strlen($s)
233      {
234          return grapheme_strlen($s);
235      }
236      public static function strpos($s, $needle, $offset = 0)
237      {
238          // ignore invalid negative offset to keep compatility
239          // with php < 5.5.35, < 5.6.21, < 7.0.6
240          return grapheme_strpos($s, $needle, $offset > 0 ? $offset : 0);
241      }
242      public static function strrpos($s, $needle, $offset = 0)
243      {
244          return grapheme_strrpos($s, $needle, $offset);
245      }
246   
247      public static function stripos($s, $needle, $offset = 0)
248      {
249          if (50418 > PHP_VERSION_ID || 50500 == PHP_VERSION_ID) {
250              // Don't use grapheme_stripos because of https://bugs.php.net/61860
251              if (!preg_match('//u', $s .= '')) {
252                  return false;
253              }
254              if ($offset < 0) {
255                  $offset = 0;
256              }
257              if (!$needle = mb_stripos($s, $needle .= '', $offset, 'UTF-8')) {
258                  return $needle;
259              }
260   
261              return grapheme_strlen(iconv_substr($s, 0, $needle, 'UTF-8'));
262          }
263   
264          return grapheme_stripos($s, $needle, $offset);
265      }
266   
267      public static function strripos($s, $needle, $offset = 0)
268      {
269          if (50418 > PHP_VERSION_ID || 50500 == PHP_VERSION_ID) {
270              // Don't use grapheme_strripos because of https://bugs.php.net/61860
271              if (!preg_match('//u', $s .= '')) {
272                  return false;
273              }
274              if ($offset < 0) {
275                  $offset = 0;
276              }
277              if (!$needle = mb_strripos($s, $needle .= '', $offset, 'UTF-8')) {
278                  return $needle;
279              }
280   
281              return grapheme_strlen(iconv_substr($s, 0, $needle, 'UTF-8'));
282          }
283   
284          return grapheme_strripos($s, $needle, $offset);
285      }
286   
287      public static function stristr($s, $needle, $before_needle = false)
288      {
289          if ('' === $needle .= '') {
290              return false;
291          }
292   
293          return mb_stristr($s, $needle, $before_needle, 'UTF-8');
294      }
295   
296      public static function strstr($s, $needle, $before_needle = false)
297      {
298          return grapheme_strstr($s, $needle, $before_needle);
299      }
300      public static function strrchr($s, $needle, $before_needle = false)
301      {
302          return mb_strrchr($s, $needle, $before_needle, 'UTF-8');
303      }
304      public static function strrichr($s, $needle, $before_needle = false)
305      {
306          return mb_strrichr($s, $needle, $before_needle, 'UTF-8');
307      }
308   
309      public static function strtolower($s)
310      {
311          return mb_strtolower($s, 'UTF-8');
312      }
313      public static function strtoupper($s)
314      {
315          return mb_strtoupper($s, 'UTF-8');
316      }
317   
318      public static function wordwrap($s, $width = 75, $break = "\n", $cut = false)
319      {
320          if (false === wordwrap('-', $width, $break, $cut)) {
321              return false;
322          }
323   
324          is_string($break) or $break = (string) $break;
325   
326          $w = '';
327          $s = explode($break, $s);
328          $iLen = count($s);
329          $chars = array();
330   
331          if (1 === $iLen && '' === $s[0]) {
332              return '';
333          }
334   
335          for ($i = 0; $i < $iLen; ++$i) {
336              if ($i) {
337                  $chars[] = $break;
338                  $w .= '#';
339              }
340   
341              $c = $s[$i];
342              unset($s[$i]);
343   
344              foreach (self::str_split($c) as $c) {
345                  $chars[] = $c;
346                  $w .= ' ' === $c ? ' ' : '?';
347              }
348          }
349   
350          $s = '';
351          $j = 0;
352          $b = $i = -1;
353          $w = wordwrap($w, $width, '#', $cut);
354   
355          while (false !== $b = strpos($w, '#', $b + 1)) {
356              for (++$i; $i < $b; ++$i) {
357                  $s .= $chars[$j];
358                  unset($chars[$j++]);
359              }
360   
361              if ($break === $chars[$j] || ' ' === $chars[$j]) {
362                  unset($chars[$j++]);
363              }
364              $s .= $break;
365          }
366   
367          return $s.implode('', $chars);
368      }
369   
370      public static function chr($c)
371      {
372          if (0x80 > $c %= 0x200000) {
373              return chr($c);
374          }
375          if (0x800 > $c) {
376              return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
377          }
378          if (0x10000 > $c) {
379              return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
380          }
381   
382          return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
383      }
384   
385      public static function count_chars($s, $mode = 0)
386      {
387          if (1 != $mode) {
388              user_error(__METHOD__.'(): the only allowed $mode is 1', E_USER_WARNING);
389          }
390          $s = self::str_split($s);
391   
392          return array_count_values($s);
393      }
394   
395      public static function ltrim($s, $charlist = null)
396      {
397          $charlist = null === $charlist ? '\s' : self::rxClass($charlist);
398   
399          return preg_replace("/^{$charlist}+/u", '', $s);
400      }
401   
402      public static function ord($s)
403      {
404          $a = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
405          if (0xF0 <= $a) {
406              return (($a - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
407          }
408          if (0xE0 <= $a) {
409              return (($a - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
410          }
411          if (0xC0 <= $a) {
412              return (($a - 0xC0) << 6) + $s[2] - 0x80;
413          }
414   
415          return $a;
416      }
417   
418      public static function rtrim($s, $charlist = null)
419      {
420          $charlist = null === $charlist ? '\s' : self::rxClass($charlist);
421   
422          return preg_replace("/{$charlist}+$/u", '', $s);
423      }
424   
425      public static function trim($s, $charlist = null)
426      {
427          return self::rtrim(self::ltrim($s, $charlist), $charlist);
428      }
429   
430      public static function str_ireplace($search, $replace, $subject, &$count = null)
431      {
432          $search = (array) $search;
433   
434          foreach ($search as $i => $s) {
435              if ('' === $s .= '') {
436                  $s = '/^(?<=.)$/';
437              } else {
438                  $s = '/'.preg_quote($s, '/').'/ui';
439              }
440   
441              $search[$i] = $s;
442          }
443   
444          $subject = preg_replace($search, $replace, $subject, -1, $replace);
445          $count = $replace;
446   
447          return $subject;
448      }
449   
450      public static function str_pad($s, $len, $pad = ' ', $type = STR_PAD_RIGHT)
451      {
452          $slen = grapheme_strlen($s);
453          if ($len <= $slen) {
454              return $s;
455          }
456   
457          $padlen = grapheme_strlen($pad);
458          $freelen = $len - $slen;
459          $len = $freelen % $padlen;
460   
461          if (STR_PAD_RIGHT == $type) {
462              return $s.str_repeat($pad, $freelen / $padlen).($len ? grapheme_substr($pad, 0, $len) : '');
463          }
464          if (STR_PAD_LEFT == $type) {
465              return str_repeat($pad, $freelen / $padlen).($len ? grapheme_substr($pad, 0, $len) : '').$s;
466          }
467          if (STR_PAD_BOTH == $type) {
468              $freelen /= 2;
469   
470              $type = ceil($freelen);
471              $len = $type % $padlen;
472              $s .= str_repeat($pad, $type / $padlen).($len ? grapheme_substr($pad, 0, $len) : '');
473   
474              $type = floor($freelen);
475              $len = $type % $padlen;
476   
477              return str_repeat($pad, $type / $padlen).($len ? grapheme_substr($pad, 0, $len) : '').$s;
478          }
479   
480          user_error(__METHOD__.'(): Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH', E_USER_WARNING);
481      }
482   
483      public static function str_shuffle($s)
484      {
485          $s = self::str_split($s);
486          shuffle($s);
487   
488          return implode('', $s);
489      }
490   
491      public static function str_split($s, $len = 1)
492      {
493          if (1 > $len = (int) $len) {
494              $len = func_get_arg(1);
495   
496              return str_split($s, $len);
497          }
498   
499          static $hasIntl;
500          isset($hasIntl) or $hasIntl = extension_loaded('intl');
501   
502          if ($hasIntl) {
503              $a = array();
504              $p = 0;
505              $l = strlen($s);
506   
507              while ($p < $l) {
508                  $a[] = grapheme_extract($s, 1, GRAPHEME_EXTR_COUNT, $p, $p);
509              }
510          } else {
511              preg_match_all('/'.GRAPHEME_CLUSTER_RX.'/u', $s, $a);
512              $a = $a[0];
513          }
514   
515          if (1 == $len) {
516              return $a;
517          }
518   
519          $s = array();
520          $p = -1;
521   
522          foreach ($a as $l => $a) {
523              if ($l % $len) {
524                  $s[$p] .= $a;
525              } else {
526                  $s[++$p] = $a;
527              }
528          }
529   
530          return $s;
531      }
532   
533      public static function str_word_count($s, $format = 0, $charlist = '')
534      {
535          $charlist = self::rxClass($charlist, '\pL');
536          $s = preg_split("/({$charlist}+(?:[\p{Pd}’']{$charlist}+)*)/u", $s, -1, PREG_SPLIT_DELIM_CAPTURE);
537   
538          $charlist = array();
539          $len = count($s);
540   
541          if (1 == $format) {
542              for ($i = 1; $i < $len; $i += 2) {
543                  $charlist[] = $s[$i];
544              }
545          } elseif (2 == $format) {
546              $offset = grapheme_strlen($s[0]);
547              for ($i = 1; $i < $len; $i += 2) {
548                  $charlist[$offset] = $s[$i];
549                  $offset += grapheme_strlen($s[$i]) + grapheme_strlen($s[$i + 1]);
550              }
551          } else {
552              $charlist = ($len - 1) / 2;
553          }
554   
555          return $charlist;
556      }
557   
558      public static function strcmp($a, $b)
559      {
560          return $a.'' === $b.'' ? 0 : strcmp(n::normalize($a, n::NFD), n::normalize($b, n::NFD));
561      }
562      public static function strnatcmp($a, $b)
563      {
564          return $a.'' === $b.'' ? 0 : strnatcmp(self::strtonatfold($a), self::strtonatfold($b));
565      }
566      public static function strcasecmp($a, $b)
567      {
568          return self::strcmp(static::strtocasefold($a), static::strtocasefold($b));
569      }
570      public static function strnatcasecmp($a, $b)
571      {
572          return self::strnatcmp(static::strtocasefold($a), static::strtocasefold($b));
573      }
574      public static function strncasecmp($a, $b, $len)
575      {
576          return self::strncmp(static::strtocasefold($a), static::strtocasefold($b), $len);
577      }
578      public static function strncmp($a, $b, $len)
579      {
580          return self::strcmp(self::substr($a, 0, $len), self::substr($b, 0, $len));
581      }
582   
583      public static function strcspn($s, $charlist, $start = 0, $len = 2147483647)
584      {
585          if ('' === $charlist .= '') {
586              return;
587          }
588          if ($start || 2147483647 != $len) {
589              $s = self::substr($s, $start, $len);
590          }
591   
592          return preg_match('/^(.*?)'.self::rxClass($charlist).'/us', $s, $len) ? grapheme_strlen($len[1]) : grapheme_strlen($s);
593      }
594   
595      public static function strpbrk($s, $charlist)
596      {
597          if (preg_match('/'.self::rxClass($charlist).'/us', $s, $m)) {
598              return substr($s, strpos($s, $m[0]));
599          } else {
600              return false;
601          }
602      }
603   
604      public static function strrev($s)
605      {
606          $s = self::str_split($s);
607   
608          return implode('', array_reverse($s));
609      }
610   
611      public static function strspn($s, $mask, $start = 0, $len = 2147483647)
612      {
613          if ($start || 2147483647 != $len) {
614              $s = self::substr($s, $start, $len);
615          }
616   
617          return preg_match('/^'.self::rxClass($mask).'+/u', $s, $s) ? grapheme_strlen($s[0]) : 0;
618      }
619   
620      public static function strtr($s, $from, $to = null)
621      {
622          if (null !== $to) {
623              $from = self::str_split($from);
624              $to   = self::str_split($to);
625   
626              $a = count($from);
627              $b = count($to);
628   
629              if ($a > $b) {
630                  $from = array_slice($from, 0, $b);
631              } elseif ($a < $b) {
632                  $to   = array_slice($to, 0, $a);
633              }
634   
635              $from = array_combine($from, $to);
636          }
637   
638          return strtr($s, $from);
639      }
640   
641      public static function substr_compare($a, $b, $offset, $len = 2147483647, $i = 0)
642      {
643          $a = self::substr($a, $offset, $len);
644   
645          return $i ? static::strcasecmp($a, $b) : self::strcmp($a, $b);
646      }
647   
648      public static function substr_count($s, $needle, $offset = 0, $len = 2147483647)
649      {
650          return substr_count(self::substr($s, $offset, $len), $needle);
651      }
652   
653      public static function substr_replace($s, $replace, $start, $len = 2147483647)
654      {
655          $s       = self::str_split($s);
656          $replace = self::str_split($replace);
657          array_splice($s, $start, $len, $replace);
658   
659          return implode('', $s);
660      }
661   
662      public static function ucfirst($s)
663      {
664          $c = iconv_substr($s, 0, 1, 'UTF-8');
665   
666          return static::ucwords($c).substr($s, strlen($c));
667      }
668   
669      public static function lcfirst($s)
670      {
671          $c = iconv_substr($s, 0, 1, 'UTF-8');
672   
673          return static::strtolower($c).substr($s, strlen($c));
674      }
675   
676      public static function ucwords($s)
677      {
678          return preg_replace_callback(
679              "/\b(.)/u",
680              function ($matches) {
681                  return mb_convert_case($matches[1], MB_CASE_TITLE, 'UTF-8');
682              },
683              $s
684          );
685      }
686   
687      public static function number_format($number, $decimals = 0, $dec_point = '.', $thousands_sep = ',')
688      {
689          if (PHP_VERSION_ID < 50400) {
690              if (isset($thousands_sep[1]) || isset($dec_point[1])) {
691                  return str_replace(
692                      array('.', ','),
693                      array($dec_point, $thousands_sep),
694                      number_format($number, $decimals, '.', ',')
695                  );
696              }
697          }
698   
699          return number_format($number, $decimals, $dec_point, $thousands_sep);
700      }
701   
702      public static function utf8_encode($s)
703      {
704          $s = utf8_encode($s);
705          if (false === strpos($s, "\xC2")) {
706              return $s;
707          } else {
708              return str_replace(self::$cp1252, self::$utf8, $s);
709          }
710      }
711   
712      public static function utf8_decode($s)
713      {
714          $s = str_replace(self::$utf8, self::$cp1252, $s);
715   
716          return utf8_decode($s);
717      }
718   
719      public static function strwidth($s)
720      {
721          if (false !== strpos($s, "\r")) {
722              $s = str_replace("\r\n", "\n", $s);
723              $s = strtr($s, "\r", "\n");
724          }
725          $width = 0;
726   
727          foreach (explode("\n", $s) as $s) {
728              $s = preg_replace('/\x1B\[[\d;]*m/', '', $s);
729              $c = substr_count($s, "\xAD") - substr_count($s, "\x08");
730              $s = preg_replace('/[\x00\x05\x07\p{Mn}\p{Me}\p{Cf}\x{1160}-\x{11FF}\x{200B}]+/u', '', $s);
731              preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
732   
733              if ($width < $c = iconv_strlen($s, 'UTF-8') + $wide + $c) {
734                  $width = $c;
735              }
736          }
737   
738          return $width;
739      }
740   
741      protected static function rxClass($s, $class = '')
742      {
743          $class = array($class);
744   
745          foreach (self::str_split($s) as $s) {
746              if ('-' === $s) {
747                  $class[0] = '-'.$class[0];
748              } elseif (!isset($s[2])) {
749                  $class[0] .= preg_quote($s, '/');
750              } elseif (1 === iconv_strlen($s, 'UTF-8')) {
751                  $class[0] .= $s;
752              } else {
753                  $class[] = $s;
754              }
755          }
756   
757          $class[0] = '['.$class[0].']';
758   
759          if (1 === count($class)) {
760              return $class[0];
761          } else {
762              return '(?:'.implode('|', $class).')';
763          }
764      }
765   
766      protected static function getData($file)
767      {
768          $file = __DIR__.'/Utf8/data/'.$file.'.ser';
769          if (file_exists($file)) {
770              return unserialize(file_get_contents($file));
771          } else {
772              return false;
773          }
774      }
775  }
776