diff --git a/README.md b/README.md
index 2891eed..5ac507e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# ddTypograph
+# MODXEvo.snippets.ddTypograph
Snippet for text typography. The snippet doesn’t use third-party services, also it sends no requests. In other words, everything is performed on your server.
___
diff --git a/assets/snippets/ddTypograph/EMT.php b/assets/snippets/ddTypograph/EMT.php
index b14ef0e..8e81587 100644
--- a/assets/snippets/ddTypograph/EMT.php
+++ b/assets/snippets/ddTypograph/EMT.php
@@ -6,3423 +6,3423 @@
* Release Date: July 2, 2015
* Authors: Evgeny Muravjev & Alexander Drutsa
*/
-
-
-class EMT_Lib
-{
- const LAYOUT_STYLE = 1;
- const LAYOUT_CLASS = 2;
-
- const INTERNAL_BLOCK_OPEN = '%%%INTBLOCKO235978%%%';
- const INTERNAL_BLOCK_CLOSE = '%%%INTBLOCKC235978%%%';
- /**
- * Таблица символов
- *
- * @var array
- */
- public static $_charsTable = array(
- '"' => array('html' => array('«', '»', '”', '‘', '„', '“', '"', '«', '»'),
- 'utf8' => array(0x201E, 0x201C, 0x201F, 0x201D, 0x00AB, 0x00BB)),
- ' ' => array('html' => array(' ', ' ', ' '),
- 'utf8' => array(0x00A0, 0x2002, 0x2003, 0x2008, 0x2009)),
- '-' => array('html' => array(/*'—',*/ '–', '−', '', '—', '–'),
- 'utf8' => array(0x002D, /*0x2014,*/ 0x2010, 0x2012, 0x2013)),
- '—' => array('html' => array('—'),
- 'utf8' => array(0x2014)),
- '==' => array('html' => array('≡'),
- 'utf8' => array(0x2261)),
- '...' => array('html' => array('…', '
'),
- 'utf8' => array(0x2026)),
- '!=' => array('html' => array('≠', '≠'),
- 'utf8' => array(0x2260)),
- '<=' => array('html' => array('≤', '≤'),
- 'utf8' => array(0x2264)),
- '>=' => array('html' => array('≥', '≥'),
- 'utf8' => array(0x2265)),
- '1/2' => array('html' => array('½', '½'),
- 'utf8' => array(0x00BD)),
- '1/4' => array('html' => array('¼', '¼'),
- 'utf8' => array(0x00BC)),
- '3/4' => array('html' => array('¾', '¾'),
- 'utf8' => array(0x00BE)),
- '+-' => array('html' => array('±', '±'),
- 'utf8' => array(0x00B1)),
- '&' => array('html' => array('&', '&')),
- '(tm)' => array('html' => array('™', ''),
- 'utf8' => array(0x2122)),
- //'(r)' => array('html' => array('®', '®', '®'),
- '(r)' => array('html' => array('®', '®'),
- 'utf8' => array(0x00AE)),
- '(c)' => array('html' => array('©', '©'),
- 'utf8' => array(0x00A9)),
- '§' => array('html' => array('§', '§'),
- 'utf8' => array(0x00A7)),
- '`' => array('html' => array('́')),
- '\'' => array('html' => array('’', '’')),
- 'x' => array('html' => array('×', '×'),
- 'utf8' => array('×') /* какой же у него может быть код? */),
-
- );
-
- /**
- * Добавление к тегам атрибута 'id', благодаря которому
- * при повторном типографирование текста будут удалены теги,
- * расставленные данным типографом
- *
- * @var array
- */
- protected static $_typographSpecificTagId = false;
-
-
- /**
- * Костыли для работы с символами UTF-8
- *
- * @author somebody?
- * @param int $c код символа в кодировке UTF-8 (например, 0x00AB)
- * @return bool|string
- */
- public static function _getUnicodeChar($c)
- {
- if ($c <= 0x7F) {
- return chr($c);
- } else if ($c <= 0x7FF) {
- return chr(0xC0 | $c >> 6)
- . chr(0x80 | $c & 0x3F);
- } else if ($c <= 0xFFFF) {
- return chr(0xE0 | $c >> 12)
- . chr(0x80 | $c >> 6 & 0x3F)
- . chr(0x80 | $c & 0x3F);
- } else if ($c <= 0x10FFFF) {
- return chr(0xF0 | $c >> 18)
- . chr(0x80 | $c >> 12 & 0x3F)
- . chr(0x80 | $c >> 6 & 0x3F)
- . chr(0x80 | $c & 0x3F);
- } else {
- return false;
- }
- }
-
-
- /**
- * Удаление кодов HTML из текста
- *
- *
- * // Remove UTF-8 chars:
- * $str = EMT_Lib::clear_special_chars('your text', 'utf8');
- * // ... or HTML codes only:
- * $str = EMT_Lib::clear_special_chars('your text', 'html');
- * // ... or combo:
- * $str = EMT_Lib::clear_special_chars('your text');
- *
- *
- * @param string $text
- * @param mixed $mode
- * @return string|bool
- */
- public static function clear_special_chars($text, $mode = null)
- {
- if(is_string($mode)) $mode = array($mode);
- if(is_null($mode)) $mode = array('utf8', 'html');
- if(!is_array($mode)) return false;
- $moder = array();
- foreach($mode as $mod) if(in_array($mod, array('utf8','html'))) $moder[] = $mod;
- if(count($moder)==0) return false;
-
- foreach (self::$_charsTable as $char => $vals)
- {
- foreach ($mode as $type)
- {
- if (isset($vals[$type]))
- {
- foreach ($vals[$type] as $v)
- {
- if ('utf8' === $type && is_int($v))
- {
- $v = self::_getUnicodeChar($v);
- }
- if ('html' === $type)
- {
- if(preg_match("/<[a-z]+>/i",$v))
- {
- $v = self::safe_tag_chars($v, true);
- }
- }
- $text = str_replace($v, $char, $text);
- }
- }
- }
- }
-
- return $text;
- }
-
- /**
- * Удаление тегов HTML из текста
- * Тег
будет преобразов в перенос строки \n, сочетание тегов
-
- * в двойной перенос
- *
- * @param string $text
- * @param array $allowableTag массив из тегов, которые будут проигнорированы
- * @return string
- */
- public static function remove_html_tags($text, $allowableTag = null)
- {
- $ignore = null;
-
- if (null !== $allowableTag)
- {
- if (is_string($allowableTag))
- {
- $allowableTag = array($allowableTag);
- }
- if (is_array($allowableTag))
- {
- $tags = array();
- foreach ($allowableTag as $tag)
- {
- if ('<' !== substr($tag, 0, 1) || '>' !== substr($tag, -1, 1)) continue;
- if ('/' === substr($tag, 1, 1)) continue;
- $tags [] = $tag;
- }
- $ignore = implode('', $tags);
- }
- }
- $text = preg_replace(array('/\
/i', '/\<\/p\>\s*\
/'), array("\n","\n\n"), $text); - $text = strip_tags($text, $ignore); - return $text; - } - - /** - * Сохраняем содержимое тегов HTML - * - * Тег 'a' кодируется со специальным префиксом для дальнейшей - * возможности выносить за него кавычки. - * - * @param string $text - * @param bool $safe - * @return string - */ - public static function safe_tag_chars($text, $way) - { - if ($way) - $text = preg_replace_callback('/(\<\/?)([^<>]+?)(\>)/s', create_function('$m','return (strlen($m[1])==1 && substr(trim($m[2]), 0, 1) == \'-\' && substr(trim($m[2]), 1, 1) != \'-\')? $m[0] : $m[1].( substr(trim($m[2]), 0, 1) === "a" ? "%%___" : "" ) . EMT_Lib::encrypt_tag(trim($m[2])) . $m[3];'), $text); - else - $text = preg_replace_callback('/(\<\/?)([^<>]+?)(\>)/s', create_function('$m','return (strlen($m[1])==1 && substr(trim($m[2]), 0, 1) == \'-\' && substr(trim($m[2]), 1, 1) != \'-\')? $m[0] : $m[1].( substr(trim($m[2]), 0, 3) === "%%___" ? EMT_Lib::decrypt_tag(substr(trim($m[2]), 4)) : EMT_Lib::decrypt_tag(trim($m[2])) ) . $m[3];'), $text); - return $text; - } - - - /** - * Декодриует спец блоки - * - * @param string $text - * @return string - */ - public static function decode_internal_blocks($text) - { - $text = preg_replace_callback('/'.EMT_Lib::INTERNAL_BLOCK_OPEN.'([a-zA-Z0-9\/=]+?)'.EMT_Lib::INTERNAL_BLOCK_CLOSE.'/s', create_function('$m','return EMT_Lib::decrypt_tag($m[1]);'), $text); - return $text; - } - - /** - * Кодирует спец блок - * - * @param string $text - * @return string - */ - public static function iblock($text) - { - return EMT_Lib::INTERNAL_BLOCK_OPEN. EMT_Lib::encrypt_tag($text).EMT_Lib::INTERNAL_BLOCK_CLOSE; - } - - - /** - * Создание тега с защищенным содержимым - * - * @param string $content текст, который будет обрамлен тегом - * @param string $tag тэг - * @param array $attribute список атрибутов, где ключ - имя атрибута, а значение - само значение данного атрибута - * @return string - */ - public static function build_safe_tag($content, $tag = 'span', $attribute = array(), $layout = EMT_Lib::LAYOUT_STYLE ) - { - $htmlTag = $tag; - - if (self::$_typographSpecificTagId) - { - if(!isset($attribute['id'])) - { - $attribute['id'] = 'emt-2' . mt_rand(1000,9999); - } - } - - $classname = ""; - if (count($attribute)) - { - - if($layout & EMT_lib::LAYOUT_STYLE) - { - if(isset($attribute['__style']) && $attribute['__style']) - { - if(isset($attribute['style']) && $attribute['style']) - { - $st = trim($attribute['style']); - if(mb_substr($st, -1) != ";") $st .= ";"; - $st .= $attribute['__style']; - $attribute['style'] = $st; - } else { - $attribute['style'] = $attribute['__style']; - } - unset($attribute['__style']); - } - - } - foreach ($attribute as $attr => $value) - { - if($attr == "__style") continue; - if($attr == "class") { - $classname = "$value"; - continue; - } - $htmlTag .= " $attr=\"$value\""; - } - - } - - if( ($layout & EMT_lib::LAYOUT_CLASS ) && $classname) { - $htmlTag .= " class=\"$classname\""; - } - - return "<" . self::encrypt_tag($htmlTag) . ">$content" . self::encrypt_tag($tag) . ">"; - } - - /** - * Метод, осуществляющий кодирование (сохранение) информации - * с целью невозможности типографировать ее - * - * @param string $text - * @return string - */ - public static function encrypt_tag($text) - { - return base64_encode($text)."="; - } - - /** - * Метод, осуществляющий декодирование информации - * - * @param string $text - * @return string - */ - public static function decrypt_tag($text) - { - return base64_decode(substr($text,0,-1)); - } - - - - public static function strpos_ex(&$haystack, $needle, $offset = null) - { - if(is_array($needle)) - { - $m = false; - $w = false; - foreach($needle as $n) - { - $p = strpos($haystack, $n , $offset); - if($p===false) continue; - if($m === false) - { - $m = $p; - $w = $n; - continue; - } - if($p < $m) - { - $m = $p; - $w = $n; - } - } - if($m === false) return false; - return array('pos' => $m, 'str' => $w); - } - return strpos($haystack, $needle, $offset); - } - - public static function _process_selector_pattern(&$pattern) - { - if($pattern===false) return; - $pattern = preg_quote($pattern , '/'); - $pattern = str_replace("\\*", "[a-z0-9_\-]*", $pattern); - $pattern = "/".$pattern."/i"; - } - public static function _test_pattern($pattern, $text) - { - if($pattern === false) return true; - return preg_match($pattern, $text); - } - - public static function strtolower($string) - { - $convert_to = array( - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", - "v", "w", "x", "y", "z", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", - "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "ø", "ù", "ú", "û", "ü", "ý", "а", "б", "в", "г", "д", "е", "ё", "ж", - "з", "и", "й", "к", "л", "м", "н", "о", "п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ы", - "ь", "э", "ю", "я" - ); - $convert_from = array( - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", - "V", "W", "X", "Y", "Z", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", - "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", - "З", "И", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ъ", - "Ь", "Э", "Ю", "Я" - ); - - return str_replace($convert_from, $convert_to, $string); - } - - // взято с http://www.w3.org/TR/html4/sgml/entities.html - protected static $html4_char_ents = array( - 'nbsp' => 160, - 'iexcl' => 161, - 'cent' => 162, - 'pound' => 163, - 'curren' => 164, - 'yen' => 165, - 'brvbar' => 166, - 'sect' => 167, - 'uml' => 168, - 'copy' => 169, - 'ordf' => 170, - 'laquo' => 171, - 'not' => 172, - 'shy' => 173, - 'reg' => 174, - 'macr' => 175, - 'deg' => 176, - 'plusmn' => 177, - 'sup2' => 178, - 'sup3' => 179, - 'acute' => 180, - 'micro' => 181, - 'para' => 182, - 'middot' => 183, - 'cedil' => 184, - 'sup1' => 185, - 'ordm' => 186, - 'raquo' => 187, - 'frac14' => 188, - 'frac12' => 189, - 'frac34' => 190, - 'iquest' => 191, - 'Agrave' => 192, - 'Aacute' => 193, - 'Acirc' => 194, - 'Atilde' => 195, - 'Auml' => 196, - 'Aring' => 197, - 'AElig' => 198, - 'Ccedil' => 199, - 'Egrave' => 200, - 'Eacute' => 201, - 'Ecirc' => 202, - 'Euml' => 203, - 'Igrave' => 204, - 'Iacute' => 205, - 'Icirc' => 206, - 'Iuml' => 207, - 'ETH' => 208, - 'Ntilde' => 209, - 'Ograve' => 210, - 'Oacute' => 211, - 'Ocirc' => 212, - 'Otilde' => 213, - 'Ouml' => 214, - 'times' => 215, - 'Oslash' => 216, - 'Ugrave' => 217, - 'Uacute' => 218, - 'Ucirc' => 219, - 'Uuml' => 220, - 'Yacute' => 221, - 'THORN' => 222, - 'szlig' => 223, - 'agrave' => 224, - 'aacute' => 225, - 'acirc' => 226, - 'atilde' => 227, - 'auml' => 228, - 'aring' => 229, - 'aelig' => 230, - 'ccedil' => 231, - 'egrave' => 232, - 'eacute' => 233, - 'ecirc' => 234, - 'euml' => 235, - 'igrave' => 236, - 'iacute' => 237, - 'icirc' => 238, - 'iuml' => 239, - 'eth' => 240, - 'ntilde' => 241, - 'ograve' => 242, - 'oacute' => 243, - 'ocirc' => 244, - 'otilde' => 245, - 'ouml' => 246, - 'divide' => 247, - 'oslash' => 248, - 'ugrave' => 249, - 'uacute' => 250, - 'ucirc' => 251, - 'uuml' => 252, - 'yacute' => 253, - 'thorn' => 254, - 'yuml' => 255, - 'fnof' => 402, - 'Alpha' => 913, - 'Beta' => 914, - 'Gamma' => 915, - 'Delta' => 916, - 'Epsilon' => 917, - 'Zeta' => 918, - 'Eta' => 919, - 'Theta' => 920, - 'Iota' => 921, - 'Kappa' => 922, - 'Lambda' => 923, - 'Mu' => 924, - 'Nu' => 925, - 'Xi' => 926, - 'Omicron' => 927, - 'Pi' => 928, - 'Rho' => 929, - 'Sigma' => 931, - 'Tau' => 932, - 'Upsilon' => 933, - 'Phi' => 934, - 'Chi' => 935, - 'Psi' => 936, - 'Omega' => 937, - 'alpha' => 945, - 'beta' => 946, - 'gamma' => 947, - 'delta' => 948, - 'epsilon' => 949, - 'zeta' => 950, - 'eta' => 951, - 'theta' => 952, - 'iota' => 953, - 'kappa' => 954, - 'lambda' => 955, - 'mu' => 956, - 'nu' => 957, - 'xi' => 958, - 'omicron' => 959, - 'pi' => 960, - 'rho' => 961, - 'sigmaf' => 962, - 'sigma' => 963, - 'tau' => 964, - 'upsilon' => 965, - 'phi' => 966, - 'chi' => 967, - 'psi' => 968, - 'omega' => 969, - 'thetasym' => 977, - 'upsih' => 978, - 'piv' => 982, - 'bull' => 8226, - 'hellip' => 8230, - 'prime' => 8242, - 'Prime' => 8243, - 'oline' => 8254, - 'frasl' => 8260, - 'weierp' => 8472, - 'image' => 8465, - 'real' => 8476, - 'trade' => 8482, - 'alefsym' => 8501, - 'larr' => 8592, - 'uarr' => 8593, - 'rarr' => 8594, - 'darr' => 8595, - 'harr' => 8596, - 'crarr' => 8629, - 'lArr' => 8656, - 'uArr' => 8657, - 'rArr' => 8658, - 'dArr' => 8659, - 'hArr' => 8660, - 'forall' => 8704, - 'part' => 8706, - 'exist' => 8707, - 'empty' => 8709, - 'nabla' => 8711, - 'isin' => 8712, - 'notin' => 8713, - 'ni' => 8715, - 'prod' => 8719, - 'sum' => 8721, - 'minus' => 8722, - 'lowast' => 8727, - 'radic' => 8730, - 'prop' => 8733, - 'infin' => 8734, - 'ang' => 8736, - 'and' => 8743, - 'or' => 8744, - 'cap' => 8745, - 'cup' => 8746, - 'int' => 8747, - 'there4' => 8756, - 'sim' => 8764, - 'cong' => 8773, - 'asymp' => 8776, - 'ne' => 8800, - 'equiv' => 8801, - 'le' => 8804, - 'ge' => 8805, - 'sub' => 8834, - 'sup' => 8835, - 'nsub' => 8836, - 'sube' => 8838, - 'supe' => 8839, - 'oplus' => 8853, - 'otimes' => 8855, - 'perp' => 8869, - 'sdot' => 8901, - 'lceil' => 8968, - 'rceil' => 8969, - 'lfloor' => 8970, - 'rfloor' => 8971, - 'lang' => 9001, - 'rang' => 9002, - 'loz' => 9674, - 'spades' => 9824, - 'clubs' => 9827, - 'hearts' => 9829, - 'diams' => 9830, - 'quot' => 34, - 'amp' => 38, - 'lt' => 60, - 'gt' => 62, - 'OElig' => 338, - 'oelig' => 339, - 'Scaron' => 352, - 'scaron' => 353, - 'Yuml' => 376, - 'circ' => 710, - 'tilde' => 732, - 'ensp' => 8194, - 'emsp' => 8195, - 'thinsp' => 8201, - 'zwnj' => 8204, - 'zwj' => 8205, - 'lrm' => 8206, - 'rlm' => 8207, - 'ndash' => 8211, - 'mdash' => 8212, - 'lsquo' => 8216, - 'rsquo' => 8217, - 'sbquo' => 8218, - 'ldquo' => 8220, - 'rdquo' => 8221, - 'bdquo' => 8222, - 'dagger' => 8224, - 'Dagger' => 8225, - 'permil' => 8240, - 'lsaquo' => 8249, - 'rsaquo' => 8250, - 'euro' => 8364, - ); - /** - * Вернуть уникод символ по html entinty - * - * @param string $entity - * @return string - */ - public static function html_char_entity_to_unicode($entity) - { - if(isset(self::$html4_char_ents[$entity])) return self::_getUnicodeChar(self::$html4_char_ents[$entity]); - return false; - } - - /** - * Сконвериторвать все html entity в соответсвующие юникод символы - * - * @param string $text - */ - public static function convert_html_entities_to_unicode(&$text) - { - $text = preg_replace_callback("/\([0-9]+)\;/", - create_function('$m', 'return EMT_Lib::_getUnicodeChar(intval($m[1]));') - , $text); - $text = preg_replace_callback("/\([0-9A-F]+)\;/", - create_function('$m', 'return EMT_Lib::_getUnicodeChar(hexdec($m[1]));') - , $text); - $text = preg_replace_callback("/\&([a-zA-Z0-9]+)\;/", - create_function('$m', '$r = EMT_Lib::html_char_entity_to_unicode($m[1]); return $r ? $r : $m[0];') - , $text); - } - - public static function rstrpos ($haystack, $needle, $offset = 0){ - - if(trim($haystack) != "" && trim($needle) != "" && $offset <= mb_strlen($haystack)) - { - $last_pos = $offset; - $found = false; - while(($curr_pos = mb_strpos($haystack, $needle, $last_pos)) !== false) - { - $found = true; - $last_pos = $curr_pos + 1; - } - if($found) - { - return $last_pos - 1; - } - else - { - return false; - } - } - else - { - return false; - } - } - - public static function ifop($cond, $true, $false) { - return $cond ? $true : $false; - } - - function split_number($num) { - return number_format($num, 0, '', ' '); - } - -} - - - -/** - * Базовый класс для группы правил обработки текста - * Класс группы должен наследовать, данный класс и задавать - * в нём EMT_Tret::rules и EMT_Tret::$name - * - */ -class EMT_Tret { - - /** - * Набор правил в данной группе, который задан изначально - * Его можно менять динамически добавляя туда правила с помощью put_rule - * - * @var unknown_type - */ - public $rules; - public $title; - - - private $disabled = array(); - private $enabled = array(); - protected $_text= ''; - public $logging = false; - public $logs = false; - public $errors = false; - public $debug_enabled = false; - public $debug_info = array(); - - - private $use_layout = false; - private $use_layout_set = false; - private $class_layout_prefix = false; - - public $class_names = array(); - public $classes = array(); - public $settings = array(); - - /** - * Защищенные теги - * - * @todo привязать к методам из Jare_Typograph_Tool - */ - const BASE64_PARAGRAPH_TAG = 'cA==='; // p - const BASE64_BREAKLINE_TAG = 'YnIgLw==='; // br / (с пробелом и слэшем) - const BASE64_NOBR_OTAG = 'bm9icg==='; // nobr - const BASE64_NOBR_CTAG = 'L25vYnI=='; // /nobr - - /** - * Типы кавычек - */ - const QUOTE_FIRS_OPEN = '«'; - const QUOTE_FIRS_CLOSE = '»'; - const QUOTE_CRAWSE_OPEN = '„'; - const QUOTE_CRAWSE_CLOSE = '“'; - - - private function log($str, $data = null) - { - if(!$this->logging) return; - $this->logs[] = array('info' => $str, 'data' => $data); - } - - private function error($info, $data = null) - { - $this->errors[] = array('info' => $info, 'data' => $data); - $this->log('ERROR: '. $info , $data); - } - - public function debug($place, &$after_text) - { - if(!$this->debug_enabled) return; - $this->debug_info[] = array( - 'place' => $place, - 'text' => $after_text, - ); - } - - - /** - * Установить режим разметки для данного Трэта если не было раньше установлено, - * EMT_Lib::LAYOUT_STYLE - с помощью стилей - * EMT_Lib::LAYOUT_CLASS - с помощью классов - * - * @param int $kind - */ - public function set_tag_layout_ifnotset($layout) - { - if($this->use_layout_set) return; - $this->use_layout = $layout; - } - - /** - * Установить режим разметки для данного Трэта, - * EMT_Lib::LAYOUT_STYLE - с помощью стилей - * EMT_Lib::LAYOUT_CLASS - с помощью классов - * EMT_Lib::LAYOUT_STYLE|EMT_Lib::LAYOUT_CLASS - оба метода - * - * @param int $kind - */ - public function set_tag_layout($layout = EMT_Lib::LAYOUT_STYLE) - { - $this->use_layout = $layout; - $this->use_layout_set = true; - } - - public function set_class_layout_prefix($prefix) - { - $this->class_layout_prefix = $prefix; - } - - - public function debug_on() - { - $this->debug_enabled = true; - } - - public function log_on() - { - $this->debug_enabled = true; - } - - - private function getmethod($name) - { - if(!$name) return false; - if(!method_exists($this, $name)) return false; - return array($this, $name); - } - - private function _pre_parse() - { - $this->pre_parse(); - foreach($this->rules as $rule) - { - if(!isset($rule['init'])) continue; - $m = $this->getmethod($rule['init']); - if(!$m) continue; - call_user_func($m); - } - } - private function _post_parse() - { - foreach($this->rules as $rule) - { - if(!isset($rule['deinit'])) continue; - $m = $this->getmethod($rule['deinit']); - if(!$m) continue; - call_user_func($m); - } - $this->post_parse(); - } - - private function rule_order_sort($a, $b) - { - if($a['order'] == $b['order']) return 0; - if($a['order'] < $b['order']) return -1; - return 1; - } - - private function apply_rule($rule) - { - $name = $rule['id']; - //$this->log("Правило $name", "Применяем правило"); - $disabled = (isset($this->disabled[$rule['id']]) && $this->disabled[$rule['id']]) || ((isset($rule['disabled']) && $rule['disabled']) && !(isset($this->enabled[$rule['id']]) && $this->enabled[$rule['id']])); - if($disabled) - { - $this->log("Правило $name", "Правило отключено" . ((isset($rule['disabled']) && $rule['disabled'])? " (по умолчанию)" : "")); - return; - } - if(isset($rule['function']) && $rule['function']) - { - if(!(isset($rule['pattern']) && $rule['pattern'])) - { - if(method_exists($this, $rule['function'])) - { - $this->log("Правило $name", "Используется метод ".$rule['function']." в правиле"); - - call_user_func(array($this, $rule['function'])); - return; - } - if(function_exists($rule['function'])) - { - $this->log("Правило $name", "Используется функция ".$rule['function']." в правиле"); - - call_user_func($rule['function']); - return; - } - - $this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена"); - return ; - } else { - if(preg_match("/^[a-z_0-9]+$/i", $rule['function'])) - { - if(method_exists($this, $rule['function'])) - { - $this->log("Правило $name", "Замена с использованием preg_replace_callback с методом ".$rule['function'].""); - - $this->_text = preg_replace_callback($rule['pattern'], array($this, $rule['function']), $this->_text); - return; - } - if(function_exists($rule['function'])) - { - $this->log("Правило $name", "Замена с использованием preg_replace_callback с функцией ".$rule['function'].""); - - $this->_text = preg_replace_callback($rule['pattern'], $rule['function'], $this->_text); - return; - } - $this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена"); - } else { - $this->_text = preg_replace_callback($rule['pattern'], create_function('$m', $rule['function']), $this->_text); - $this->log('Замена с использованием preg_replace_callback с инлайн функцией из правила '.$rule['id']); - return; - } - return ; - } - } - - if(isset($rule['simple_replace']) && $rule['simple_replace']) - { - if(isset($rule['case_sensitive']) && $rule['case_sensitive']) - { - $this->log("Правило $name", "Простая замена с использованием str_replace"); - $this->_text = str_replace($rule['pattern'], $rule['replacement'], $this->_text); - return; - } - $this->log("Правило $name", "Простая замена с использованием str_ireplace"); - $this->_text = str_ireplace($rule['pattern'], $rule['replacement'], $this->_text); - return; - } - - $pattern = $rule['pattern']; - if(is_string($pattern)) $pattern = array($pattern); - $eval = false; - foreach($pattern as $patt) - { - $chr = substr($patt,0,1); - $preg_arr = explode($chr, $patt); - if(strpos($preg_arr[count($preg_arr)-1], "e")!==false) - { - $eval = true; - break; - } - } - if(!$eval) - { - $this->log("Правило $name", "Замена с использованием preg_replace"); - - do { - $this->_text = preg_replace($rule['pattern'], $rule['replacement'], $this->_text); - if(!(isset($rule['cycled']) && $rule['cycled'])) break; - } while(preg_match($rule['pattern'], $this->_text)); - - return; - } - - $this->log("Правило $name", "Замена с использованием preg_replace_callback вместо eval"); - $k = 0; - foreach($pattern as $patt) - { - $repl = is_string($rule['replacement']) ? $rule['replacement'] : $rule['replacement'][$k]; - - $chr = substr($patt,0,1); - $preg_arr = explode($chr, $patt); - if(strpos($preg_arr[count($preg_arr)-1], "e")!==false) // eval система - { - $preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]); - $patt = implode($chr, $preg_arr); - $this->thereplacement = $repl; - do { - $this->_text = preg_replace_callback($patt, array($this, "thereplcallback"), $this->_text); - if(!(isset($rule['cycled']) && $rule['cycled'])) break; - } while(preg_match($patt, $this->_text)); - - } else { - do { - $this->_text = preg_replace($patt, $repl, $this->_text); - if(!(isset($rule['cycled']) && $rule['cycled'])) break; - } while(preg_match($patt, $this->_text)); - } - $k++; - } - } - - - protected function preg_replace_e($pattern, $replacement, $text) - { - $chr = substr($pattern,0,1); - $preg_arr = explode($chr, $pattern); - if(strpos($preg_arr[count($preg_arr)-1], "e")===false) return preg_replace($pattern, $replacement, $text); - $preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]); - $patt = implode($chr, $preg_arr); - $this->thereplacement = $replacement; - return preg_replace_callback($patt, array($this, "thereplcallback"), $text); - } - - private $thereplacement = ""; - private function thereplcallback($m) - { - $x = ""; - eval('$x = '.($this->thereplacement?$this->thereplacement:'""').';'); - return $x; - } - - private function _apply($list) - { - $this->errors = array(); - $this->_pre_parse(); - - $this->log("Применяется набор правил", implode(",",$list)); - - $rulelist = array(); - foreach($list as $k) - { - $rule = $this->rules[$k]; - $rule['id'] = $k; - $rule['order'] = isset($rule['order'])? $rule['order'] : 5 ; - $rulelist[] = $rule; - } - //usort($rulelist, array($this, "rule_order_sort")); - - foreach($rulelist as $rule) - { - $this->apply_rule($rule); - $this->debug($rule['id'], $this->_text); - } - - $this->_post_parse(); - } - - - /** - * Создание защищенного тега с содержимым - * - * @see EMT_lib::build_safe_tag - * @param string $content - * @param string $tag - * @param array $attribute - * @return string - */ - protected function tag($content, $tag = 'span', $attribute = array()) - { - if(isset($attribute['class'])) - { - $classname = $attribute['class']; - if($classname == "nowrap") - { - if(!$this->is_on('nowrap')) - { - $tag = "nobr"; - $attribute = array(); - $classname = ""; - } - } - if(isset($this->classes[$classname])) - { - $style_inline = $this->classes[$classname]; - if($style_inline) $attribute['__style'] = $style_inline; - } - $classname = (isset($this->class_names[$classname]) ? $this->class_names[$classname] :$classname); - $classname = ($this->class_layout_prefix ? $this->class_layout_prefix : "" ).$classname; - $attribute['class'] = $classname; - } - - return EMT_Lib::build_safe_tag($content, $tag, $attribute, - $this->use_layout === false? EMT_Lib::LAYOUT_STYLE : $this->use_layout ); - } - - - /** - * Добавить правило в группу - * - * @param string $name - * @param array $params - */ - public function put_rule($name, $params) - { - $this->rules[$name] = $params; - return $this; - } - - /** - * Отключить правило, в обработке - * - * @param string $name - */ - public function disable_rule($name) - { - $this->disabled[$name] = true; - unset($this->enabled[$name]); - } - - /** - * Включить правило - * - * @param string $name - */ - public function enable_rule($name) - { - $this->enabled[$name] = true; - unset($this->disabled[$name]); - } - - /** - * Добавить настройку в трет - * - * @param string $key ключ - * @param mixed $value значение - */ - public function set($key, $value) - { - $this->settings[$key] = $value; - } - - /** - * Установлена ли настройка - * - * @param string $key - */ - public function is_on($key) - { - if(!isset($this->settings[$key])) return false; - $kk = $this->settings[$key]; - return ((strtolower($kk)=="on") || ($kk === "1") || ($kk === true) || ($kk === 1)); - } - - /** - * Получить строковое значение настройки - * - * @param unknown_type $key - * @return unknown - */ - public function ss($key) - { - if(!isset($this->settings[$key])) return ""; - return strval($this->settings[$key]); - } - - /** - * Добавить настройку в правило - * - * @param string $rulename идентификатор правила - * @param string $key ключ - * @param mixed $value значение - */ - public function set_rule($rulename, $key, $value) - { - $this->rules[$rulename][$key] = $value; - } - - /** - * Включить правила, согласно списку - * - * @param array $list список правил - * @param boolean $disable выкллючить их или включить - * @param boolean $strict строго, т.е. те которые не в списку будут тоже обработаны - */ - public function activate($list,$disable =false, $strict = true) - { - if(!is_array($list)) return ; - - foreach($list as $rulename) - { - if($disable) $this->disable_rule($rulename); else $this->enable_rule($rulename); - } - - if($strict) - { - foreach($this->rules as $rulename => $v) - { - if(in_array($rulename, $list)) continue; - if(!$disable) $this->disable_rule($rulename); else $this->enable_rule($rulename); - } - } - } - - public function set_text(&$text) - { - $this->_text = &$text; - $this->debug_info = array(); - $this->logs = array(); - } - - - /** - * Применить к тексту - * - * @param string $text - текст к которому применить - * @param mixed $list - список правил, null - все правила - * @return string - */ - public function apply($list = null) - { - if(is_string($list)) $rlist = array($list); - elseif(is_array($list)) $rlist = $list; - else $rlist = array_keys($this->rules); - $this->_apply($rlist); - return $this->_text; - } - - - - - /** - * Код, выполняем до того, как применить правила - * - */ - public function pre_parse() - { - } - - /** - * После выполнения всех правил, выполняется этот метод - * - */ - public function post_parse() - { - } - - -} - - - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Abbr extends EMT_Tret -{ - public $title = "Сокращения"; - - public $domain_zones = array('ru','ру','com','ком','org','орг', 'уа', 'ua'); - - public $classes = array( - 'nowrap' => 'word-spacing:nowrap;', - ); - - public $rules = array( - 'nobr_abbreviation' => array( - 'description' => 'Расстановка пробелов перед сокращениями dpi, lpi', - 'pattern' => '/(\s+|^|\>)(\d+)(\040|\t)*(dpi|lpi)([\s\;\.\?\!\:\(]|$)/i', - 'replacement' => '\1\2 \4\5' - ), - 'nobr_acronym' => array( - 'description' => 'Расстановка пробелов перед сокращениями гл., стр., рис., илл., ст., п.', - 'pattern' => '/(\s|^|\>|\()(гл|стр|рис|илл?|ст|п|с)\.(\040|\t)*(\d+)(\ \;|\s|\.|\,|\?|\!|$)/iu', - 'replacement' => '\1\2. \4\5' - ), - 'nobr_sm_im' => array( - 'description' => 'Расстановка пробелов перед сокращениями см., им.', - 'pattern' => '/(\s|^|\>|\()(см|им)\.(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', - 'replacement' => '\1\2. \4\5' - ), - 'nobr_locations' => array( - 'description' => 'Расстановка пробелов в сокращениях г., ул., пер., д.', - 'pattern' => array( - '/(\s|^|\>)(г|ул|пер|просп|пл|бул|наб|пр|ш|туп)\.(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', - '/(\s|^|\>)(б\-р|пр\-кт)(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', - '/(\s|^|\>)(д|кв|эт)\.(\040|\t)*(\d+)(\s|\.|\,|\?|\!|$)/iu', - ), - 'replacement' => array( - '\1\2. \4\5', - '\1\2 \4\5', - '\1\2. \4\5', - ) - ), - 'nbsp_before_unit' => array( - 'description' => 'Замена символов и привязка сокращений в размерных величинах: м, см, м2…', - 'pattern' => array( - '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(м|мм|см|дм|км|гм|km|dm|cm|mm)(\s|\.|\!|\?|\,|$|\±\;|\;|\<)/iu', - '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(м|мм|см|дм|км|гм|km|dm|cm|mm)([32]|³|²)(\s|\.|\!|\?|\,|$|\±\;|\;|\<)/iue' - ), - 'replacement' => array( - '\1\2 \4\5', - '$m[1].$m[2]." ".$m[4].($m[5]=="3"||$m[5]=="2"? "&sup".$m[5].";" : $m[5] ).$m[6]' - ), - ), - 'nbsp_before_weight_unit' => array( - 'description' => 'Замена символов и привязка сокращений в весовых величинах: г, кг, мг…', - 'pattern' => '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(г|кг|мг|т)(\s|\.|\!|\?|\,|$|\ \;|\;)/iu', - 'replacement' => '\1\2 \4\5', - ), - 'nobr_before_unit_volt' => array( - 'description' => 'Установка пробельных символов в сокращении вольт', - 'pattern' => '/(\d+)([вВ]| В)(\s|\.|\!|\?|\,|$)/u', - 'replacement' => '\1 В\3' - ), - 'ps_pps' => array( - 'description' => 'Объединение сокращений P.S., P.P.S.', - 'pattern' => '/(^|\040|\t|\>|\r|\n)(p\.\040?)(p\.\040?)?(s\.)([^\<])/ie', - 'replacement' => '$m[1] . $this->tag(trim($m[2]) . " " . ($m[3] ? trim($m[3]) . " " : ""). $m[4], "span", array("class" => "nowrap") ).$m[5] ' - ), - 'nobr_vtch_itd_itp' => array( - 'description' => 'Объединение сокращений и т.д., и т.п., в т.ч.', - 'cycled' => true, - 'pattern' => array( - '/(^|\s|\ \;)и( |\ \;)т\.?[ ]?д(\.|$|\s|\ \;)/ue', - '/(^|\s|\ \;)и( |\ \;)т\.?[ ]?п(\.|$|\s|\ \;)/ue', - '/(^|\s|\ \;)в( |\ \;)т\.?[ ]?ч(\.|$|\s|\ \;)/ue', - ), - 'replacement' => array( - '$m[1].$this->tag("и т. д.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', - '$m[1].$this->tag("и т. п.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', - '$m[1].$this->tag("в т. ч.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', - ) - ), - 'nbsp_te' => array( - 'description' => 'Обработка т.е.', - 'pattern' => '/(^|\s|\ \;)([тТ])\.?[ ]?е\./ue', - 'replacement' => '$m[1].$this->tag($m[2].". е.", "span", array("class" => "nowrap"))', - ), - 'nbsp_money_abbr' => array( - 'description' => 'Форматирование денежных сокращений (расстановка пробелов и привязка названия валюты к числу)', - 'pattern' => '/(\d)((\040|\ \;)?(тыс|млн|млрд)\.?(\040|\ \;)?)?(\040|\ \;)?(руб\.|долл\.|евро|€|€|\$|у[\.]? ?е[\.]?)/ieu', - 'replacement' => '$m[1].($m[4]?" ".$m[4].($m[4]=="тыс"?".":""):"")." ".(!preg_match("#у[\\\\.]? ?е[\\\\.]?#iu",$m[7])?$m[7]:"у.е.")', - ), - 'nbsp_money_abbr_rev' => array( - 'description' => 'Привязка валюты к числу спереди', - 'pattern' => '/(€|€|\$)\s?(\d)/iu', - 'replacement' => '\1 \2' - ), - 'nbsp_org_abbr' => array( - 'description' => 'Привязка сокращений форм собственности к названиям организаций', - 'pattern' => '/([^a-zA-Zа-яёА-ЯЁ]|^)(ООО|ЗАО|ОАО|НИИ|ПБОЮЛ) ([a-zA-Zа-яёА-ЯЁ]|\"|\«\;|\&bdquo\;|<)/u', - 'replacement' => '\1\2 \3' - ), - 'nobr_gost' => array( - 'description' => 'Привязка сокращения ГОСТ к номеру', - 'pattern' => array( - '/(\040|\t|\ \;|^)ГОСТ( |\ \;)?(\d+)((\-|\&minus\;|\&mdash\;)(\d+))?(( |\ \;)(\-|\&mdash\;))?/ieu', - '/(\040|\t|\ \;|^|\>)ГОСТ( |\ \;)?(\d+)(\-|\&minus\;|\&mdash\;)(\d+)/ieu', - ), - 'replacement' => array( - '$m[1].$this->tag("ГОСТ ".$m[3].(isset($m[6])?"–".$m[6]:"").(isset($m[7])?" —":""),"span", array("class"=>"nowrap"))', - '$m[1]."ГОСТ ".$m[3]."–".$m[5]', - ), - ), - /* - 'nobr_vtch_itd_itp' => array( - 'description' => 'Привязка сокращений до н.э., н.э.', - 'pattern' => array( - - //IV в до н.э, в V-VIвв до нэ., третий в. н.э. - - '/(\s|\ \;)и( |\ \;)т\.?[ ]?д\./ue', - '/(\s|\ \;)и( |\ \;)т\.?[ ]?п\./ue', - '/(\s|\ \;)в( |\ \;)т\.?[ ]?ч\./ue', - ), - 'replacement' => array( - '$m[1].$this->tag("и т. д.", "span", array("class" => "nowrap"))', - '$m[1].$this->tag("и т. п.", "span", array("class" => "nowrap"))', - '$m[1].$this->tag("в т. ч.", "span", array("class" => "nowrap"))', - ) - ), - */ - - - ); -} - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Dash extends EMT_Tret -{ - public $title = "Дефисы и тире"; - public $rules = array( - 'mdash_symbol_to_html_mdash' => array( - 'description' => 'Замена символа тире на html конструкцию', - 'pattern' => '/—/iu', - 'replacement' => '—' - ), - 'mdash' => array( - 'description' => 'Тире после кавычек, скобочек, пунктуации', - 'pattern' => array( - '/([a-zа-яё0-9]+|\,|\:|\)|\&(ra|ld)quo\;|\|\"|\>)(\040|\t)(—|\-|\&mdash\;)(\s|$|\<)/ui', - '/(\,|\:|\)|\")(—|\-|\&mdash\;)(\s|$|\<)/ui', - ), - 'replacement' => array( - '\1 —\5', - '\1 —\3', - ), - ), - 'mdash_2' => array( - 'description' => 'Тире после переноса строки', - 'pattern' => '/(\n|\r|^|\>)(\-|\&mdash\;)(\t|\040)/', - 'replacement' => '\1— ' - ), - 'mdash_3' => array( - 'description' => 'Тире после знаков восклицания, троеточия и прочее', - 'pattern' => '/(\.|\!|\?|\&hellip\;)(\040|\t|\ \;)(\-|\&mdash\;)(\040|\t|\ \;)/', - 'replacement' => '\1 — ' - ), - 'iz_za_pod' => array( - 'description' => 'Расстановка дефисов между из-за, из-под', - 'pattern' => '/(\s|\ \;|\>|^)(из)(\040|\t|\ \;)\-?(за|под)([\.\,\!\?\:\;]|\040|\ \;)/uie', - 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' - ), - 'to_libo_nibud' => array( - 'description' => 'Автоматическая простановка дефисов в обезличенных местоимениях и междометиях', - 'cycled' => true, - 'pattern' => '/(\s|^|\ \;|\>)(кто|кем|когда|зачем|почему|как|что|чем|где|чего|кого)\-?(\040|\t|\ \;)\-?(то|либо|нибудь)([\.\,\!\?\;]|\040|\ \;|$)/uie', - 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' - ), - 'koe_kak' => array( - 'description' => 'Кое-как, кой-кого, все-таки', - 'cycled' => true, - 'pattern' => array( - '/(\s|^|\ \;|\>)(кое)\-?(\040|\t|\ \;)\-?(как)([\.\,\!\?\;]|\040|\ \;|$)/uie', - '/(\s|^|\ \;|\>)(кой)\-?(\040|\t|\ \;)\-?(кого)([\.\,\!\?\;]|\040|\ \;|$)/uie', - '/(\s|^|\ \;|\>)(вс[её])\-?(\040|\t|\ \;)\-?(таки)([\.\,\!\?\;]|\040|\ \;|$)/uie', - ), - 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' - ), - 'ka_de_kas' => array( - 'description' => 'Расстановка дефисов с частицами ка, де, кась', - 'disabled' => true, - 'pattern' => array( - '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(ка)([\.\,\!\?\;]|\040|\ \;|$)/uie', - '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(де)([\.\,\!\?\;]|\040|\ \;|$)/uie', - '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(кась)([\.\,\!\?\;]|\040|\ \;|$)/uie', - ), - 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' - ), - - - - ); - -} - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Date extends EMT_Tret -{ - public $title = "Даты и дни"; - - public $classes = array( - 'nowrap' => 'word-spacing:nowrap;', - ); - - public $rules = array( - 'years' => array( - 'description' => 'Установка тире и пробельных символов в периодах дат', - 'pattern' => '/(с|по|период|середины|начала|начало|конца|конец|половины|в|между|\([cс]\)|\©\;)(\s+|\ \;)([\d]{4})(-|\&mdash\;|\&minus\;)([\d]{4})(( |\ \;)?(г\.г\.|гг\.|гг|г\.|г)([^а-яёa-z]))?/eui', - 'replacement' => '$m[1].$m[2]. (intval($m[3])>=intval($m[5])? $m[3].$m[4].$m[5] : $m[3]."—".$m[5]) . (isset($m[6])? " гг.":"").(isset($m[9])?$m[9]:"")' - ), - 'mdash_month_interval' => array( - 'description' => 'Расстановка тире и объединение в неразрывные периоды месяцев', - 'disabled' => true, - 'pattern' => '/((январ|феврал|сентябр|октябр|ноябр|декабр)([ьяюе]|[её]м)|(апрел|июн|июл)([ьяюе]|ем)|(март|август)([ауе]|ом)?|ма[йяюе]|маем)\-((январ|феврал|сентябр|октябр|ноябр|декабр)([ьяюе]|[её]м)|(апрел|июн|июл)([ьяюе]|ем)|(март|август)([ауе]|ом)?|ма[йяюе]|маем)/iu', - 'replacement' => '\1—\8' - ), - 'nbsp_and_dash_month_interval' => array( - 'description' => 'Расстановка тире и объединение в неразрывные периоды дней', - 'disabled' => true, - 'pattern' => '/([^\>]|^)(\d+)(\-|\&minus\;|\&mdash\;)(\d+)( |\ \;)(января|февраля|марта|апреля|мая|июня|июля|августа|сентября|октября|ноября|декабря)([^\<]|$)/ieu', - 'replacement' => '$m[1].$this->tag($m[2]."—".$m[4]." ".$m[6],"span", array("class"=>"nowrap")).$m[7]' - ), - 'nobr_year_in_date' => array( - 'description' => 'Привязка года к дате', - 'pattern' => array( - '/(\s|\ \;)([0-9]{2}\.[0-9]{2}\.([0-9]{2})?[0-9]{2})(\s|\ \;)?г(\.|\s|\ \;)/eiu', - '/(\s|\ \;)([0-9]{2}\.[0-9]{2}\.([0-9]{2})?[0-9]{2})(\s|\ \;|\.(\s|\ \;|$)|$)/eiu', - ), - 'replacement' => array( - '$m[1].$this->tag($m[2]." г.","span", array("class"=>"nowrap")).($m[5]==="."?"":" ")', - '$m[1].$this->tag($m[2],"span", array("class"=>"nowrap")).$m[4]', - ), - ), - 'space_posle_goda' => array( - 'description' => 'Пробел после года', - 'pattern' => '/(^|\040|\ \;)([0-9]{3,4})(год([ауе]|ом)?)([^a-zа-яё]|$)/ui', - 'replacement' => '\1\2 \3\5' - ), - 'nbsp_posle_goda_abbr' => array( - 'description' => 'Пробел после года', - 'pattern' => '/(^|\040|\ \;|\"|\«\;)([0-9]{3,4})[ ]?(г\.)([^a-zа-яё]|$)/ui', - 'replacement' => '\1\2 \3\4' - ), - - ); -} - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Etc extends EMT_Tret -{ - - - public $classes = array( - 'nowrap' => 'word-spacing:nowrap;', - ); - - - /** - * Базовые параметры тофа - * - * @var array - */ - public $title = "Прочее"; - public $rules = array( - 'acute_accent' => array( - 'description' => 'Акцент', - 'pattern' => '/(у|е|ы|а|о|э|я|и|ю|ё)\`(\w)/i', - 'replacement' => '\1́\2' - ), - - - - 'word_sup' => array( - 'description' => 'Надстрочный текст после символа ^', - 'pattern' => '/((\s|\ \;|^)+)\^([a-zа-яё0-9\.\:\,\-]+)(\s|\ \;|$|\.$)/ieu', - 'replacement' => '"" . $this->tag($this->tag($m[3],"small"),"sup") . $m[4]' - ), - 'century_period' => array( - 'description' => 'Тире между диапозоном веков', - 'pattern' => '/(\040|\t|\ \;|^)([XIV]{1,5})(-|\&mdash\;)([XIV]{1,5})(( |\ \;)?(в\.в\.|вв\.|вв|в\.|в))/eu', - 'replacement' => '$m[1] .$this->tag($m[2]."—".$m[4]." вв.","span", array("class"=>"nowrap"))' - ), - 'time_interval' => array( - 'description' => 'Тире и отмена переноса между диапозоном времени', - 'pattern' => '/([^\d\>]|^)([\d]{1,2}\:[\d]{2})(-|\&mdash\;|\&minus\;)([\d]{1,2}\:[\d]{2})([^\d\<]|$)/eui', - 'replacement' => '$m[1] . $this->tag($m[2]."—".$m[4],"span", array("class"=>"nowrap")).$m[5]' - ), - 'split_number_to_triads' => array( - 'description' => 'Разбиение числа на триады', - 'pattern' => '/([^a-zA-Z0-9<\)]|^)([0-9]{5,})([^a-zA-Z>\(]|$)/eu', - 'replacement' => '$m[1].str_replace(" "," ",EMT_Lib::split_number($m[2])).$m[3] ' - //'function' => 'split_number' - ), - 'expand_no_nbsp_in_nobr' => array( - 'description' => 'Удаление nbsp в nobr/nowrap тэгах', - 'function' => 'remove_nbsp' - ), - 'nobr_to_nbsp' => array( - 'description' => 'Преобразование nobr в nbsp', - 'disabled' => true, - 'function' => 'nobr_to_nbsp' - ), - ); - - protected function remove_nbsp() - { - $thetag = $this->tag("###", 'span', array('class' => "nowrap")); - $arr = explode("###", $thetag); - $b = preg_quote($arr[0], '/'); - $e = preg_quote($arr[1], '/'); - - $match = '/(^|[^a-zа-яё])([a-zа-яё]+)\ \;('.$b.')/iu'; - do { - $this->_text = preg_replace($match, '\1\3\2 ', $this->_text); - } while(preg_match($match, $this->_text)); - - $match = '/('.$e.')\ \;([a-zа-яё]+)($|[^a-zа-яё])/iu'; - do { - $this->_text = preg_replace($match, ' \2\1\3', $this->_text); - } while(preg_match($match, $this->_text)); - - $this->_text = $this->preg_replace_e('/'.$b.'.*?'.$e.'/iue', 'str_replace(" "," ",$m[0]);' , $this->_text ); - } - - protected function nobr_to_nbsp() - { - $thetag = $this->tag("###", 'span', array('class' => "nowrap")); - $arr = explode("###", $thetag); - $b = preg_quote($arr[0], '/'); - $e = preg_quote($arr[1], '/'); - $this->_text = $this->preg_replace_e('/'.$b.'(.*?)'.$e.'/iue', 'str_replace(" "," ",$m[1]);' , $this->_text ); - } - /* - protected function split_number () { - - $this->preg_replace_e("/([^a-zA-Z<]|^)([0-9]{5,})([^a-zA-Z>]|$)/u", ) - - $match = ; - while(preg_match($match, $this->_text, $m)) { - $repl = ""; - for($i = strlen($m[2]); $i >=0 ; $i-=3) - if($i-3>=0) $repl = ($i>3?" ":"").substr($m[2], $i-3, 3) . $repl; else $repl = substr($m[2], 0, $i) . $repl; - $this->_text = str_replace($m[1], $repl, $this->_text); - } - }*/ - -} - - - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Nobr extends EMT_Tret -{ - public $title = "Неразрывные конструкции"; - - public $classes = array( - 'nowrap' => 'word-spacing:nowrap;', - ); - - public $rules = array( - - 'super_nbsp' => array( - 'description' => 'Привязка союзов и предлогов к написанным после словам', - 'pattern' => '/(\s|^|\&(la|bd)quo\;|\>|\(|\&mdash\;\ \;)([a-zа-яё]{1,2}\s+)([a-zа-яё]{1,2}\s+)?([a-zа-яё0-9\-]{2,}|[0-9])/ieu', - 'replacement' => '$m[1] . trim($m[3]) . " " . ($m[4] ? trim($m[4]) . " " : "") . $m[5]' - ), - 'nbsp_in_the_end' => array( - 'description' => 'Привязка союзов и предлогов к предыдущим словам в случае конца предложения', - 'pattern' => '/([a-zа-яё0-9\-]{3,}) ([a-zа-яё]{1,2})\.( [A-ZА-ЯЁ]|$)/u', - 'replacement' => '\1 \2.\3' - ), - 'phone_builder' => array( - 'description' => 'Объединение в неразрывные конструкции номеров телефонов', - 'pattern' => - array( - '/([^\d\+]|^)([\+]?[0-9]{1,3})( |\ \;|\&thinsp\;)([0-9]{3,4}|\([0-9]{3,4}\))( |\ \;|\&thinsp\;)([0-9]{2,3})(-|\&minus\;)([0-9]{2})(-|\&minus\;)([0-9]{2})([^\d]|$)/e', - '/([^\d\+]|^)([\+]?[0-9]{1,3})( |\ \;|\&thinsp\;)([0-9]{3,4}|[0-9]{3,4})( |\ \;|\&thinsp\;)([0-9]{2,3})(-|\&minus\;)([0-9]{2})(-|\&minus\;)([0-9]{2})([^\d]|$)/e', - ), - 'replacement' => - array( - '$m[1] .(($m[1] == ">" || $m[11] == "<") ? $m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10] :$this->tag($m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10], "span", array("class"=>"nowrap")) ).$m[11]', - '$m[1] .(($m[1] == ">" || $m[11] == "<") ? $m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10] :$this->tag($m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10], "span", array("class"=>"nowrap")) ).$m[11]', - ), - ), - 'phone_builder_v2' => array( - 'description' => 'Дополнительный формат номеров телефонов', - 'pattern' => '/([^\d]|^)\+\s?([0-9]{1})\s?\(([0-9]{3,4})\)\s?(\d{3})(\d{2})(\d{2})([^\d]|$)/ie', - 'replacement' => '$m[1].$this->tag("+".$m[2]." ".$m[3]." ".$m[4]."-".$m[5]."-".$m[6], "span", array("class" => "nowrap")).$m[7]', - ), - 'ip_address' => array( - 'description' => 'Объединение IP-адресов', - 'pattern' => '/(\s|\ \;|^)(\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3})/ie', - 'replacement' => '$m[1] . $this->nowrap_ip_address($m[2])' - ), - 'dots_for_surname_abbr' => array( - 'disabled' => true, - 'description' => 'Простановка точек к инициалам у фамилии', - 'pattern' => - array( - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])\.?(\s|\ \;)?([А-ЯЁ])(\s|\ \;)([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])\.?(\s|\ \;)?([А-ЯЁ])\.?(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - ), - 'replacement' => - array( - '$m[1].$this->tag($m[2].". ".$m[4].". ".$m[6], "span", array("class" => "nowrap")).$m[7]', - '$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', - ), - ), - 'spaces_nobr_in_surname_abbr' => array( - 'description' => 'Привязка инициалов к фамилиям', - 'pattern' => - array( - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ])\.(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])(\s|\ \;)?([А-ЯЁ])(\s|\ \;)([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])(\s|\ \;)?([А-ЯЁ])(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - //'/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([A-Z])\.?(\s|\ \;)?([A-Z])(\.(\s|\ \;)?|(\s|\ \;))([A-Z][a-z]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - //'/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([A-Z][a-z]+)(\s|\ \;)([A-Z])\.?(\s|\ \;)?([A-Z])\.?(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', - ), - 'replacement' => - array( - '$m[1].$this->tag($m[2].". ".$m[4].". ".$m[6], "span", array("class" => "nowrap")).$m[7]', - '$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', - '$m[1].$this->tag($m[2].(isset($m[3])? " " : "" ).$m[4].(isset($m[5])? " " : "" ).$m[6], "span", array("class" => "nowrap")).$m[7]', - '$m[1].$this->tag($m[2]." ".$m[4].(isset($m[5])? " " : "" ).$m[6], "span", array("class" => "nowrap")).$m[7]', - //'$m[1].$this->tag($m[2].". ".$m[4].". ".$m[8], "span", array("class" => "nowrap")).$m[9]', - //'$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', - ), - ), - 'nbsp_before_particle' => array( - 'description' => 'Неразрывный пробел перед частицей', - 'pattern' => '/(\040|\t)+(ли|бы|б|же|ж)(\ \;|\.|\,|\:|\;|\&hellip\;|\?|\s)/iue', - 'replacement' => '" ".$m[2] . ($m[3] == " " ? " " : $m[3])' - ), - 'nbsp_v_kak_to' => array( - 'description' => 'Неразрывный пробел в как то', - 'pattern' => '/как то\:/ui', - 'replacement' => 'как то:' - ), - 'nbsp_celcius' => array( - 'description' => 'Привязка градусов к числу', - 'pattern' => '/(\s|^|\>|\ \;)(\d+)( |\ \;)?(°|\°\;)(C|С)(\s|\.|\!|\?|\,|$|\ \;|\;)/iu', - 'replacement' => '\1\2 \4C\6' - ), - 'hyphen_nowrap_in_small_words' => array( - 'description' => 'Обрамление пятисимвольных слов разделенных дефисом в неразрывные блоки', - 'disabled' => true, - 'cycled' => true, - 'pattern' => '/(\ \;|\s|\>|^)([a-zа-яё]{1}\-[a-zа-яё]{4}|[a-zа-яё]{2}\-[a-zа-яё]{3}|[a-zа-яё]{3}\-[a-zа-яё]{2}|[a-zа-яё]{4}\-[a-zа-яё]{1}|когда\-то|кое\-как|кой\-кого|вс[её]\-таки|[а-яё]+\-(кась|ка|де))(\s|\.|\,|\!|\?|\ \;|\&hellip\;|$)/uie', - 'replacement' => '$m[1] . $this->tag($m[2], "span", array("class"=>"nowrap")) . $m[4]', - ), - 'hyphen_nowrap' => array( - 'description' => 'Отмена переноса слова с дефисом', - 'disabled' => true, - 'cycled' => true, - 'pattern' => '/(\ \;|\s|\>|^)([a-zа-яё]+)((\-([a-zа-яё]+)){1,2})(\s|\.|\,|\!|\?|\ \;|\&hellip\;|$)/uie', - 'replacement' => '$m[1] . $this->tag($m[2].$m[3], "span", array("class"=>"nowrap")) . $m[6]' - ), - ); - - /** - * Объединение IP-адрессов в неразрывные конструкции (IPv4 only) - * - * @param unknown_type $triads - * @return unknown - */ - protected function nowrap_ip_address($triads) - { - $triad = explode('.', $triads); - $addTag = true; - - foreach ($triad as $value) { - $value = (int) $value; - if ($value > 255) { - $addTag = false; - break; - } - } - - if (true === $addTag) { - $triads = $this->tag($triads, 'span', array('class' => "nowrap")); - } - - return $triads; - } -} - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_Number extends EMT_Tret -{ - public $title = "Числа, дроби, математические знаки"; - - - public $rules = array( - 'minus_between_nums' => array( - 'description' => 'Расстановка знака минус между числами', - 'pattern' => '/(\d+)\-(\d)/i', - 'replacement' => '\1−\2' - ), - 'minus_in_numbers_range' => array( - 'description' => 'Расстановка знака минус между диапозоном чисел', - 'pattern' => '/(^|\s|\ \;)(\&minus\;|\-)(\d+)(\.\.\.|\&hellip\;)(\s|\ \;)?(\+|\-|\&minus\;)?(\d+)/ie', - 'replacement' => '$m[1] ."−".$m[3] . $m[4].$m[5].($m[6]=="+"?$m[6]:"−").$m[7]' - ), - 'auto_times_x' => array( - 'description' => 'Замена x на символ × в размерных единицах', - 'cycled' => true, - 'pattern' => '/([^a-zA-Z><]|^)(\×\;)?(\d+)(\040*)(x|х)(\040*)(\d+)([^a-zA-Z><]|$)/u', - 'replacement' => '\1\2\3×\7\8' - ), - 'numeric_sub' => array( - 'description' => 'Нижний индекс', - 'pattern' => '/([a-zа-яё0-9])\_([\d]{1,3})([^@а-яёa-z0-9]|$)/ieu', - 'replacement' => '$m[1] . $this->tag($this->tag($m[2],"small"),"sub") . $m[3]' - ), - 'numeric_sup' => array( - 'description' => 'Верхний индекс', - 'pattern' => '/([a-zа-яё0-9])\^([\d]{1,3})([^а-яёa-z0-9]|$)/ieu', - 'replacement' => '$m[1] . $this->tag($this->tag($m[2],"small"),"sup") . $m[3]' - ), - 'simple_fraction' => array( - 'description' => 'Замена дробей 1/2, 1/4, 3/4 на соответствующие символы', - 'pattern' => array('/(^|\D)1\/(2|4)(\D)/', '/(^|\D)3\/4(\D)/'), - 'replacement' => array('\1&frac1\2;\3', '\1¾\2') - ), - 'math_chars' => array( - 'description' => 'Математические знаки больше/меньше/плюс минус/неравно', - 'pattern' => array('/!=/', '/\<=/', '/([^=]|^)\>=/', '/~=/', '/\+-/'), - 'replacement' => array('≠', '≤', '\1≥', '≅', '±' ) - ), - - 'thinsp_between_number_triads' => array( - 'description' => 'Объединение триад чисел полупробелом', - 'pattern' => '/([0-9]{1,3}( [0-9]{3}){1,})(.|$)/ue', - 'replacement' => '($m[3]=="-"? $m[0]:str_replace(" "," ",$m[1]).$m[3])' - ), - 'thinsp_between_no_and_number' => array( - 'description' => 'Пробел между симоволом номера и числом', - 'pattern' => '/(№|\№\;)(\s| )*(\d)/iu', - 'replacement' => '№ \3' - ), - 'thinsp_between_sect_and_number' => array( - 'description' => 'Пробел между параграфом и числом', - 'pattern' => '/(§|\§\;)(\s| )*(\d+|[IVX]+|[a-zа-яё]+)/ui', - 'replacement' => '§ \3' - ), - ); -} - - -/** - * @see EMT_Tret - */ - -class EMT_Tret_OptAlign extends EMT_Tret -{ - - public $classes = array( - 'oa_obracket_sp_s' => "margin-right:0.3em;", - "oa_obracket_sp_b" => "margin-left:-0.3em;", - "oa_obracket_nl_b" => "margin-left:-0.3em;", - "oa_comma_b" => "margin-right:-0.2em;", - "oa_comma_e" => "margin-left:0.2em;", - 'oa_oquote_nl' => "margin-left:-0.44em;", - 'oa_oqoute_sp_s' => "margin-right:0.44em;", - 'oa_oqoute_sp_q' => "margin-left:-0.44em;", - ); - - /** - * Базовые параметры тофа - * - * @var array - */ - public $title = "Оптическое выравнивание"; - public $rules = array( - 'oa_oquote' => array( - 'description' => 'Оптическое выравнивание открывающей кавычки', - //'disabled' => true, - 'pattern' => array( - '/([a-zа-яё\-]{3,})(\040|\ \;|\t)(\«\;)/uie', - '/(\n|\r|^)(\«\;)/ei' - ), - 'replacement' => array( - '$m[1] . $this->tag($m[2], "span", array("class"=>"oa_oqoute_sp_s")) . $this->tag($m[3], "span", array("class"=>"oa_oqoute_sp_q"))', - '$m[1] . $this->tag($m[2], "span", array("class"=>"oa_oquote_nl"))', - ), - ), - 'oa_oquote_extra' => array( - 'description' => 'Оптическое выравнивание кавычки', - //'disabled' => true, - 'function' => 'oaquote_extra' - ), - 'oa_obracket_coma' => array( - 'description' => 'Оптическое выравнивание для пунктуации (скобка)', - //'disabled' => true, - 'pattern' => array( - '/(\040|\ \;|\t)\(/ei', - '/(\n|\r|^)\(/ei', - //'/([а-яёa-z0-9]+)\,(\040+)/iue', - ), - 'replacement' => array( - '$this->tag($m[1], "span", array("class"=>"oa_obracket_sp_s")) . $this->tag("(", "span", array("class"=>"oa_obracket_sp_b"))', - '$m[1] . $this->tag("(", "span", array("class"=>"oa_obracket_nl_b"))', - //'$m[1] . $this->tag(",", "span", array("class"=>"oa_comma_b")) . $this->tag(" ", "span", array("class"=>"oa_comma_e"))', - ), - ), - - ); - - /** - * Если стоит открывающая кавычка после
-
+ * в двойной перенос
+ *
+ * @param string $text
+ * @param array $allowableTag массив из тегов, которые будут проигнорированы
+ * @return string
+ */
+ public static function remove_html_tags($text, $allowableTag = null)
+ {
+ $ignore = null;
+
+ if (null !== $allowableTag)
+ {
+ if (is_string($allowableTag))
+ {
+ $allowableTag = array($allowableTag);
+ }
+ if (is_array($allowableTag))
+ {
+ $tags = array();
+ foreach ($allowableTag as $tag)
+ {
+ if ('<' !== substr($tag, 0, 1) || '>' !== substr($tag, -1, 1)) continue;
+ if ('/' === substr($tag, 1, 1)) continue;
+ $tags [] = $tag;
+ }
+ $ignore = implode('', $tags);
+ }
+ }
+ $text = preg_replace(array('/\
/i', '/\<\/p\>\s*\
/'), array("\n","\n\n"), $text); + $text = strip_tags($text, $ignore); + return $text; + } + + /** + * Сохраняем содержимое тегов HTML + * + * Тег 'a' кодируется со специальным префиксом для дальнейшей + * возможности выносить за него кавычки. + * + * @param string $text + * @param bool $safe + * @return string + */ + public static function safe_tag_chars($text, $way) + { + if ($way) + $text = preg_replace_callback('/(\<\/?)([^<>]+?)(\>)/s', create_function('$m','return (strlen($m[1])==1 && substr(trim($m[2]), 0, 1) == \'-\' && substr(trim($m[2]), 1, 1) != \'-\')? $m[0] : $m[1].( substr(trim($m[2]), 0, 1) === "a" ? "%%___" : "" ) . EMT_Lib::encrypt_tag(trim($m[2])) . $m[3];'), $text); + else + $text = preg_replace_callback('/(\<\/?)([^<>]+?)(\>)/s', create_function('$m','return (strlen($m[1])==1 && substr(trim($m[2]), 0, 1) == \'-\' && substr(trim($m[2]), 1, 1) != \'-\')? $m[0] : $m[1].( substr(trim($m[2]), 0, 3) === "%%___" ? EMT_Lib::decrypt_tag(substr(trim($m[2]), 4)) : EMT_Lib::decrypt_tag(trim($m[2])) ) . $m[3];'), $text); + return $text; + } + + + /** + * Декодриует спец блоки + * + * @param string $text + * @return string + */ + public static function decode_internal_blocks($text) + { + $text = preg_replace_callback('/'.EMT_Lib::INTERNAL_BLOCK_OPEN.'([a-zA-Z0-9\/=]+?)'.EMT_Lib::INTERNAL_BLOCK_CLOSE.'/s', create_function('$m','return EMT_Lib::decrypt_tag($m[1]);'), $text); + return $text; + } + + /** + * Кодирует спец блок + * + * @param string $text + * @return string + */ + public static function iblock($text) + { + return EMT_Lib::INTERNAL_BLOCK_OPEN. EMT_Lib::encrypt_tag($text).EMT_Lib::INTERNAL_BLOCK_CLOSE; + } + + + /** + * Создание тега с защищенным содержимым + * + * @param string $content текст, который будет обрамлен тегом + * @param string $tag тэг + * @param array $attribute список атрибутов, где ключ - имя атрибута, а значение - само значение данного атрибута + * @return string + */ + public static function build_safe_tag($content, $tag = 'span', $attribute = array(), $layout = EMT_Lib::LAYOUT_STYLE ) + { + $htmlTag = $tag; + + if (self::$_typographSpecificTagId) + { + if(!isset($attribute['id'])) + { + $attribute['id'] = 'emt-2' . mt_rand(1000,9999); + } + } + + $classname = ""; + if (count($attribute)) + { + + if($layout & EMT_lib::LAYOUT_STYLE) + { + if(isset($attribute['__style']) && $attribute['__style']) + { + if(isset($attribute['style']) && $attribute['style']) + { + $st = trim($attribute['style']); + if(mb_substr($st, -1) != ";") $st .= ";"; + $st .= $attribute['__style']; + $attribute['style'] = $st; + } else { + $attribute['style'] = $attribute['__style']; + } + unset($attribute['__style']); + } + + } + foreach ($attribute as $attr => $value) + { + if($attr == "__style") continue; + if($attr == "class") { + $classname = "$value"; + continue; + } + $htmlTag .= " $attr=\"$value\""; + } + + } + + if( ($layout & EMT_lib::LAYOUT_CLASS ) && $classname) { + $htmlTag .= " class=\"$classname\""; + } + + return "<" . self::encrypt_tag($htmlTag) . ">$content" . self::encrypt_tag($tag) . ">"; + } + + /** + * Метод, осуществляющий кодирование (сохранение) информации + * с целью невозможности типографировать ее + * + * @param string $text + * @return string + */ + public static function encrypt_tag($text) + { + return base64_encode($text)."="; + } + + /** + * Метод, осуществляющий декодирование информации + * + * @param string $text + * @return string + */ + public static function decrypt_tag($text) + { + return base64_decode(substr($text,0,-1)); + } + + + + public static function strpos_ex(&$haystack, $needle, $offset = null) + { + if(is_array($needle)) + { + $m = false; + $w = false; + foreach($needle as $n) + { + $p = strpos($haystack, $n , $offset); + if($p===false) continue; + if($m === false) + { + $m = $p; + $w = $n; + continue; + } + if($p < $m) + { + $m = $p; + $w = $n; + } + } + if($m === false) return false; + return array('pos' => $m, 'str' => $w); + } + return strpos($haystack, $needle, $offset); + } + + public static function _process_selector_pattern(&$pattern) + { + if($pattern===false) return; + $pattern = preg_quote($pattern , '/'); + $pattern = str_replace("\\*", "[a-z0-9_\-]*", $pattern); + $pattern = "/".$pattern."/i"; + } + public static function _test_pattern($pattern, $text) + { + if($pattern === false) return true; + return preg_match($pattern, $text); + } + + public static function strtolower($string) + { + $convert_to = array( + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", + "v", "w", "x", "y", "z", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", + "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "ø", "ù", "ú", "û", "ü", "ý", "а", "б", "в", "г", "д", "е", "ё", "ж", + "з", "и", "й", "к", "л", "м", "н", "о", "п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ы", + "ь", "э", "ю", "я" + ); + $convert_from = array( + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", + "V", "W", "X", "Y", "Z", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", + "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", + "З", "И", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ъ", + "Ь", "Э", "Ю", "Я" + ); + + return str_replace($convert_from, $convert_to, $string); + } + + // взято с http://www.w3.org/TR/html4/sgml/entities.html + protected static $html4_char_ents = array( + 'nbsp' => 160, + 'iexcl' => 161, + 'cent' => 162, + 'pound' => 163, + 'curren' => 164, + 'yen' => 165, + 'brvbar' => 166, + 'sect' => 167, + 'uml' => 168, + 'copy' => 169, + 'ordf' => 170, + 'laquo' => 171, + 'not' => 172, + 'shy' => 173, + 'reg' => 174, + 'macr' => 175, + 'deg' => 176, + 'plusmn' => 177, + 'sup2' => 178, + 'sup3' => 179, + 'acute' => 180, + 'micro' => 181, + 'para' => 182, + 'middot' => 183, + 'cedil' => 184, + 'sup1' => 185, + 'ordm' => 186, + 'raquo' => 187, + 'frac14' => 188, + 'frac12' => 189, + 'frac34' => 190, + 'iquest' => 191, + 'Agrave' => 192, + 'Aacute' => 193, + 'Acirc' => 194, + 'Atilde' => 195, + 'Auml' => 196, + 'Aring' => 197, + 'AElig' => 198, + 'Ccedil' => 199, + 'Egrave' => 200, + 'Eacute' => 201, + 'Ecirc' => 202, + 'Euml' => 203, + 'Igrave' => 204, + 'Iacute' => 205, + 'Icirc' => 206, + 'Iuml' => 207, + 'ETH' => 208, + 'Ntilde' => 209, + 'Ograve' => 210, + 'Oacute' => 211, + 'Ocirc' => 212, + 'Otilde' => 213, + 'Ouml' => 214, + 'times' => 215, + 'Oslash' => 216, + 'Ugrave' => 217, + 'Uacute' => 218, + 'Ucirc' => 219, + 'Uuml' => 220, + 'Yacute' => 221, + 'THORN' => 222, + 'szlig' => 223, + 'agrave' => 224, + 'aacute' => 225, + 'acirc' => 226, + 'atilde' => 227, + 'auml' => 228, + 'aring' => 229, + 'aelig' => 230, + 'ccedil' => 231, + 'egrave' => 232, + 'eacute' => 233, + 'ecirc' => 234, + 'euml' => 235, + 'igrave' => 236, + 'iacute' => 237, + 'icirc' => 238, + 'iuml' => 239, + 'eth' => 240, + 'ntilde' => 241, + 'ograve' => 242, + 'oacute' => 243, + 'ocirc' => 244, + 'otilde' => 245, + 'ouml' => 246, + 'divide' => 247, + 'oslash' => 248, + 'ugrave' => 249, + 'uacute' => 250, + 'ucirc' => 251, + 'uuml' => 252, + 'yacute' => 253, + 'thorn' => 254, + 'yuml' => 255, + 'fnof' => 402, + 'Alpha' => 913, + 'Beta' => 914, + 'Gamma' => 915, + 'Delta' => 916, + 'Epsilon' => 917, + 'Zeta' => 918, + 'Eta' => 919, + 'Theta' => 920, + 'Iota' => 921, + 'Kappa' => 922, + 'Lambda' => 923, + 'Mu' => 924, + 'Nu' => 925, + 'Xi' => 926, + 'Omicron' => 927, + 'Pi' => 928, + 'Rho' => 929, + 'Sigma' => 931, + 'Tau' => 932, + 'Upsilon' => 933, + 'Phi' => 934, + 'Chi' => 935, + 'Psi' => 936, + 'Omega' => 937, + 'alpha' => 945, + 'beta' => 946, + 'gamma' => 947, + 'delta' => 948, + 'epsilon' => 949, + 'zeta' => 950, + 'eta' => 951, + 'theta' => 952, + 'iota' => 953, + 'kappa' => 954, + 'lambda' => 955, + 'mu' => 956, + 'nu' => 957, + 'xi' => 958, + 'omicron' => 959, + 'pi' => 960, + 'rho' => 961, + 'sigmaf' => 962, + 'sigma' => 963, + 'tau' => 964, + 'upsilon' => 965, + 'phi' => 966, + 'chi' => 967, + 'psi' => 968, + 'omega' => 969, + 'thetasym' => 977, + 'upsih' => 978, + 'piv' => 982, + 'bull' => 8226, + 'hellip' => 8230, + 'prime' => 8242, + 'Prime' => 8243, + 'oline' => 8254, + 'frasl' => 8260, + 'weierp' => 8472, + 'image' => 8465, + 'real' => 8476, + 'trade' => 8482, + 'alefsym' => 8501, + 'larr' => 8592, + 'uarr' => 8593, + 'rarr' => 8594, + 'darr' => 8595, + 'harr' => 8596, + 'crarr' => 8629, + 'lArr' => 8656, + 'uArr' => 8657, + 'rArr' => 8658, + 'dArr' => 8659, + 'hArr' => 8660, + 'forall' => 8704, + 'part' => 8706, + 'exist' => 8707, + 'empty' => 8709, + 'nabla' => 8711, + 'isin' => 8712, + 'notin' => 8713, + 'ni' => 8715, + 'prod' => 8719, + 'sum' => 8721, + 'minus' => 8722, + 'lowast' => 8727, + 'radic' => 8730, + 'prop' => 8733, + 'infin' => 8734, + 'ang' => 8736, + 'and' => 8743, + 'or' => 8744, + 'cap' => 8745, + 'cup' => 8746, + 'int' => 8747, + 'there4' => 8756, + 'sim' => 8764, + 'cong' => 8773, + 'asymp' => 8776, + 'ne' => 8800, + 'equiv' => 8801, + 'le' => 8804, + 'ge' => 8805, + 'sub' => 8834, + 'sup' => 8835, + 'nsub' => 8836, + 'sube' => 8838, + 'supe' => 8839, + 'oplus' => 8853, + 'otimes' => 8855, + 'perp' => 8869, + 'sdot' => 8901, + 'lceil' => 8968, + 'rceil' => 8969, + 'lfloor' => 8970, + 'rfloor' => 8971, + 'lang' => 9001, + 'rang' => 9002, + 'loz' => 9674, + 'spades' => 9824, + 'clubs' => 9827, + 'hearts' => 9829, + 'diams' => 9830, + 'quot' => 34, + 'amp' => 38, + 'lt' => 60, + 'gt' => 62, + 'OElig' => 338, + 'oelig' => 339, + 'Scaron' => 352, + 'scaron' => 353, + 'Yuml' => 376, + 'circ' => 710, + 'tilde' => 732, + 'ensp' => 8194, + 'emsp' => 8195, + 'thinsp' => 8201, + 'zwnj' => 8204, + 'zwj' => 8205, + 'lrm' => 8206, + 'rlm' => 8207, + 'ndash' => 8211, + 'mdash' => 8212, + 'lsquo' => 8216, + 'rsquo' => 8217, + 'sbquo' => 8218, + 'ldquo' => 8220, + 'rdquo' => 8221, + 'bdquo' => 8222, + 'dagger' => 8224, + 'Dagger' => 8225, + 'permil' => 8240, + 'lsaquo' => 8249, + 'rsaquo' => 8250, + 'euro' => 8364, + ); + /** + * Вернуть уникод символ по html entinty + * + * @param string $entity + * @return string + */ + public static function html_char_entity_to_unicode($entity) + { + if(isset(self::$html4_char_ents[$entity])) return self::_getUnicodeChar(self::$html4_char_ents[$entity]); + return false; + } + + /** + * Сконвериторвать все html entity в соответсвующие юникод символы + * + * @param string $text + */ + public static function convert_html_entities_to_unicode(&$text) + { + $text = preg_replace_callback("/\([0-9]+)\;/", + create_function('$m', 'return EMT_Lib::_getUnicodeChar(intval($m[1]));') + , $text); + $text = preg_replace_callback("/\([0-9A-F]+)\;/", + create_function('$m', 'return EMT_Lib::_getUnicodeChar(hexdec($m[1]));') + , $text); + $text = preg_replace_callback("/\&([a-zA-Z0-9]+)\;/", + create_function('$m', '$r = EMT_Lib::html_char_entity_to_unicode($m[1]); return $r ? $r : $m[0];') + , $text); + } + + public static function rstrpos ($haystack, $needle, $offset = 0){ + + if(trim($haystack) != "" && trim($needle) != "" && $offset <= mb_strlen($haystack)) + { + $last_pos = $offset; + $found = false; + while(($curr_pos = mb_strpos($haystack, $needle, $last_pos)) !== false) + { + $found = true; + $last_pos = $curr_pos + 1; + } + if($found) + { + return $last_pos - 1; + } + else + { + return false; + } + } + else + { + return false; + } + } + + public static function ifop($cond, $true, $false) { + return $cond ? $true : $false; + } + + function split_number($num) { + return number_format($num, 0, '', ' '); + } + +} + + + +/** + * Базовый класс для группы правил обработки текста + * Класс группы должен наследовать, данный класс и задавать + * в нём EMT_Tret::rules и EMT_Tret::$name + * + */ +class EMT_Tret { + + /** + * Набор правил в данной группе, который задан изначально + * Его можно менять динамически добавляя туда правила с помощью put_rule + * + * @var unknown_type + */ + public $rules; + public $title; + + + private $disabled = array(); + private $enabled = array(); + protected $_text= ''; + public $logging = false; + public $logs = false; + public $errors = false; + public $debug_enabled = false; + public $debug_info = array(); + + + private $use_layout = false; + private $use_layout_set = false; + private $class_layout_prefix = false; + + public $class_names = array(); + public $classes = array(); + public $settings = array(); + + /** + * Защищенные теги + * + * @todo привязать к методам из Jare_Typograph_Tool + */ + const BASE64_PARAGRAPH_TAG = 'cA==='; // p + const BASE64_BREAKLINE_TAG = 'YnIgLw==='; // br / (с пробелом и слэшем) + const BASE64_NOBR_OTAG = 'bm9icg==='; // nobr + const BASE64_NOBR_CTAG = 'L25vYnI=='; // /nobr + + /** + * Типы кавычек + */ + const QUOTE_FIRS_OPEN = '«'; + const QUOTE_FIRS_CLOSE = '»'; + const QUOTE_CRAWSE_OPEN = '„'; + const QUOTE_CRAWSE_CLOSE = '“'; + + + private function log($str, $data = null) + { + if(!$this->logging) return; + $this->logs[] = array('info' => $str, 'data' => $data); + } + + private function error($info, $data = null) + { + $this->errors[] = array('info' => $info, 'data' => $data); + $this->log('ERROR: '. $info , $data); + } + + public function debug($place, &$after_text) + { + if(!$this->debug_enabled) return; + $this->debug_info[] = array( + 'place' => $place, + 'text' => $after_text, + ); + } + + + /** + * Установить режим разметки для данного Трэта если не было раньше установлено, + * EMT_Lib::LAYOUT_STYLE - с помощью стилей + * EMT_Lib::LAYOUT_CLASS - с помощью классов + * + * @param int $kind + */ + public function set_tag_layout_ifnotset($layout) + { + if($this->use_layout_set) return; + $this->use_layout = $layout; + } + + /** + * Установить режим разметки для данного Трэта, + * EMT_Lib::LAYOUT_STYLE - с помощью стилей + * EMT_Lib::LAYOUT_CLASS - с помощью классов + * EMT_Lib::LAYOUT_STYLE|EMT_Lib::LAYOUT_CLASS - оба метода + * + * @param int $kind + */ + public function set_tag_layout($layout = EMT_Lib::LAYOUT_STYLE) + { + $this->use_layout = $layout; + $this->use_layout_set = true; + } + + public function set_class_layout_prefix($prefix) + { + $this->class_layout_prefix = $prefix; + } + + + public function debug_on() + { + $this->debug_enabled = true; + } + + public function log_on() + { + $this->debug_enabled = true; + } + + + private function getmethod($name) + { + if(!$name) return false; + if(!method_exists($this, $name)) return false; + return array($this, $name); + } + + private function _pre_parse() + { + $this->pre_parse(); + foreach($this->rules as $rule) + { + if(!isset($rule['init'])) continue; + $m = $this->getmethod($rule['init']); + if(!$m) continue; + call_user_func($m); + } + } + private function _post_parse() + { + foreach($this->rules as $rule) + { + if(!isset($rule['deinit'])) continue; + $m = $this->getmethod($rule['deinit']); + if(!$m) continue; + call_user_func($m); + } + $this->post_parse(); + } + + private function rule_order_sort($a, $b) + { + if($a['order'] == $b['order']) return 0; + if($a['order'] < $b['order']) return -1; + return 1; + } + + private function apply_rule($rule) + { + $name = $rule['id']; + //$this->log("Правило $name", "Применяем правило"); + $disabled = (isset($this->disabled[$rule['id']]) && $this->disabled[$rule['id']]) || ((isset($rule['disabled']) && $rule['disabled']) && !(isset($this->enabled[$rule['id']]) && $this->enabled[$rule['id']])); + if($disabled) + { + $this->log("Правило $name", "Правило отключено" . ((isset($rule['disabled']) && $rule['disabled'])? " (по умолчанию)" : "")); + return; + } + if(isset($rule['function']) && $rule['function']) + { + if(!(isset($rule['pattern']) && $rule['pattern'])) + { + if(method_exists($this, $rule['function'])) + { + $this->log("Правило $name", "Используется метод ".$rule['function']." в правиле"); + + call_user_func(array($this, $rule['function'])); + return; + } + if(function_exists($rule['function'])) + { + $this->log("Правило $name", "Используется функция ".$rule['function']." в правиле"); + + call_user_func($rule['function']); + return; + } + + $this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена"); + return ; + } else { + if(preg_match("/^[a-z_0-9]+$/i", $rule['function'])) + { + if(method_exists($this, $rule['function'])) + { + $this->log("Правило $name", "Замена с использованием preg_replace_callback с методом ".$rule['function'].""); + + $this->_text = preg_replace_callback($rule['pattern'], array($this, $rule['function']), $this->_text); + return; + } + if(function_exists($rule['function'])) + { + $this->log("Правило $name", "Замена с использованием preg_replace_callback с функцией ".$rule['function'].""); + + $this->_text = preg_replace_callback($rule['pattern'], $rule['function'], $this->_text); + return; + } + $this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена"); + } else { + $this->_text = preg_replace_callback($rule['pattern'], create_function('$m', $rule['function']), $this->_text); + $this->log('Замена с использованием preg_replace_callback с инлайн функцией из правила '.$rule['id']); + return; + } + return ; + } + } + + if(isset($rule['simple_replace']) && $rule['simple_replace']) + { + if(isset($rule['case_sensitive']) && $rule['case_sensitive']) + { + $this->log("Правило $name", "Простая замена с использованием str_replace"); + $this->_text = str_replace($rule['pattern'], $rule['replacement'], $this->_text); + return; + } + $this->log("Правило $name", "Простая замена с использованием str_ireplace"); + $this->_text = str_ireplace($rule['pattern'], $rule['replacement'], $this->_text); + return; + } + + $pattern = $rule['pattern']; + if(is_string($pattern)) $pattern = array($pattern); + $eval = false; + foreach($pattern as $patt) + { + $chr = substr($patt,0,1); + $preg_arr = explode($chr, $patt); + if(strpos($preg_arr[count($preg_arr)-1], "e")!==false) + { + $eval = true; + break; + } + } + if(!$eval) + { + $this->log("Правило $name", "Замена с использованием preg_replace"); + + do { + $this->_text = preg_replace($rule['pattern'], $rule['replacement'], $this->_text); + if(!(isset($rule['cycled']) && $rule['cycled'])) break; + } while(preg_match($rule['pattern'], $this->_text)); + + return; + } + + $this->log("Правило $name", "Замена с использованием preg_replace_callback вместо eval"); + $k = 0; + foreach($pattern as $patt) + { + $repl = is_string($rule['replacement']) ? $rule['replacement'] : $rule['replacement'][$k]; + + $chr = substr($patt,0,1); + $preg_arr = explode($chr, $patt); + if(strpos($preg_arr[count($preg_arr)-1], "e")!==false) // eval система + { + $preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]); + $patt = implode($chr, $preg_arr); + $this->thereplacement = $repl; + do { + $this->_text = preg_replace_callback($patt, array($this, "thereplcallback"), $this->_text); + if(!(isset($rule['cycled']) && $rule['cycled'])) break; + } while(preg_match($patt, $this->_text)); + + } else { + do { + $this->_text = preg_replace($patt, $repl, $this->_text); + if(!(isset($rule['cycled']) && $rule['cycled'])) break; + } while(preg_match($patt, $this->_text)); + } + $k++; + } + } + + + protected function preg_replace_e($pattern, $replacement, $text) + { + $chr = substr($pattern,0,1); + $preg_arr = explode($chr, $pattern); + if(strpos($preg_arr[count($preg_arr)-1], "e")===false) return preg_replace($pattern, $replacement, $text); + $preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]); + $patt = implode($chr, $preg_arr); + $this->thereplacement = $replacement; + return preg_replace_callback($patt, array($this, "thereplcallback"), $text); + } + + private $thereplacement = ""; + private function thereplcallback($m) + { + $x = ""; + eval('$x = '.($this->thereplacement?$this->thereplacement:'""').';'); + return $x; + } + + private function _apply($list) + { + $this->errors = array(); + $this->_pre_parse(); + + $this->log("Применяется набор правил", implode(",",$list)); + + $rulelist = array(); + foreach($list as $k) + { + $rule = $this->rules[$k]; + $rule['id'] = $k; + $rule['order'] = isset($rule['order'])? $rule['order'] : 5 ; + $rulelist[] = $rule; + } + //usort($rulelist, array($this, "rule_order_sort")); + + foreach($rulelist as $rule) + { + $this->apply_rule($rule); + $this->debug($rule['id'], $this->_text); + } + + $this->_post_parse(); + } + + + /** + * Создание защищенного тега с содержимым + * + * @see EMT_lib::build_safe_tag + * @param string $content + * @param string $tag + * @param array $attribute + * @return string + */ + protected function tag($content, $tag = 'span', $attribute = array()) + { + if(isset($attribute['class'])) + { + $classname = $attribute['class']; + if($classname == "nowrap") + { + if(!$this->is_on('nowrap')) + { + $tag = "nobr"; + $attribute = array(); + $classname = ""; + } + } + if(isset($this->classes[$classname])) + { + $style_inline = $this->classes[$classname]; + if($style_inline) $attribute['__style'] = $style_inline; + } + $classname = (isset($this->class_names[$classname]) ? $this->class_names[$classname] :$classname); + $classname = ($this->class_layout_prefix ? $this->class_layout_prefix : "" ).$classname; + $attribute['class'] = $classname; + } + + return EMT_Lib::build_safe_tag($content, $tag, $attribute, + $this->use_layout === false? EMT_Lib::LAYOUT_STYLE : $this->use_layout ); + } + + + /** + * Добавить правило в группу + * + * @param string $name + * @param array $params + */ + public function put_rule($name, $params) + { + $this->rules[$name] = $params; + return $this; + } + + /** + * Отключить правило, в обработке + * + * @param string $name + */ + public function disable_rule($name) + { + $this->disabled[$name] = true; + unset($this->enabled[$name]); + } + + /** + * Включить правило + * + * @param string $name + */ + public function enable_rule($name) + { + $this->enabled[$name] = true; + unset($this->disabled[$name]); + } + + /** + * Добавить настройку в трет + * + * @param string $key ключ + * @param mixed $value значение + */ + public function set($key, $value) + { + $this->settings[$key] = $value; + } + + /** + * Установлена ли настройка + * + * @param string $key + */ + public function is_on($key) + { + if(!isset($this->settings[$key])) return false; + $kk = $this->settings[$key]; + return ((strtolower($kk)=="on") || ($kk === "1") || ($kk === true) || ($kk === 1)); + } + + /** + * Получить строковое значение настройки + * + * @param unknown_type $key + * @return unknown + */ + public function ss($key) + { + if(!isset($this->settings[$key])) return ""; + return strval($this->settings[$key]); + } + + /** + * Добавить настройку в правило + * + * @param string $rulename идентификатор правила + * @param string $key ключ + * @param mixed $value значение + */ + public function set_rule($rulename, $key, $value) + { + $this->rules[$rulename][$key] = $value; + } + + /** + * Включить правила, согласно списку + * + * @param array $list список правил + * @param boolean $disable выкллючить их или включить + * @param boolean $strict строго, т.е. те которые не в списку будут тоже обработаны + */ + public function activate($list,$disable =false, $strict = true) + { + if(!is_array($list)) return ; + + foreach($list as $rulename) + { + if($disable) $this->disable_rule($rulename); else $this->enable_rule($rulename); + } + + if($strict) + { + foreach($this->rules as $rulename => $v) + { + if(in_array($rulename, $list)) continue; + if(!$disable) $this->disable_rule($rulename); else $this->enable_rule($rulename); + } + } + } + + public function set_text(&$text) + { + $this->_text = &$text; + $this->debug_info = array(); + $this->logs = array(); + } + + + /** + * Применить к тексту + * + * @param string $text - текст к которому применить + * @param mixed $list - список правил, null - все правила + * @return string + */ + public function apply($list = null) + { + if(is_string($list)) $rlist = array($list); + elseif(is_array($list)) $rlist = $list; + else $rlist = array_keys($this->rules); + $this->_apply($rlist); + return $this->_text; + } + + + + + /** + * Код, выполняем до того, как применить правила + * + */ + public function pre_parse() + { + } + + /** + * После выполнения всех правил, выполняется этот метод + * + */ + public function post_parse() + { + } + + +} + + + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Abbr extends EMT_Tret +{ + public $title = "Сокращения"; + + public $domain_zones = array('ru','ру','com','ком','org','орг', 'уа', 'ua'); + + public $classes = array( + 'nowrap' => 'word-spacing:nowrap;', + ); + + public $rules = array( + 'nobr_abbreviation' => array( + 'description' => 'Расстановка пробелов перед сокращениями dpi, lpi', + 'pattern' => '/(\s+|^|\>)(\d+)(\040|\t)*(dpi|lpi)([\s\;\.\?\!\:\(]|$)/i', + 'replacement' => '\1\2 \4\5' + ), + 'nobr_acronym' => array( + 'description' => 'Расстановка пробелов перед сокращениями гл., стр., рис., илл., ст., п.', + 'pattern' => '/(\s|^|\>|\()(гл|стр|рис|илл?|ст|п|с)\.(\040|\t)*(\d+)(\ \;|\s|\.|\,|\?|\!|$)/iu', + 'replacement' => '\1\2. \4\5' + ), + 'nobr_sm_im' => array( + 'description' => 'Расстановка пробелов перед сокращениями см., им.', + 'pattern' => '/(\s|^|\>|\()(см|им)\.(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', + 'replacement' => '\1\2. \4\5' + ), + 'nobr_locations' => array( + 'description' => 'Расстановка пробелов в сокращениях г., ул., пер., д.', + 'pattern' => array( + '/(\s|^|\>)(г|ул|пер|просп|пл|бул|наб|пр|ш|туп)\.(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', + '/(\s|^|\>)(б\-р|пр\-кт)(\040|\t)*([а-яё0-9a-z]+)(\s|\.|\,|\?|\!|$)/iu', + '/(\s|^|\>)(д|кв|эт)\.(\040|\t)*(\d+)(\s|\.|\,|\?|\!|$)/iu', + ), + 'replacement' => array( + '\1\2. \4\5', + '\1\2 \4\5', + '\1\2. \4\5', + ) + ), + 'nbsp_before_unit' => array( + 'description' => 'Замена символов и привязка сокращений в размерных величинах: м, см, м2…', + 'pattern' => array( + '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(м|мм|см|дм|км|гм|km|dm|cm|mm)(\s|\.|\!|\?|\,|$|\±\;|\;|\<)/iu', + '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(м|мм|см|дм|км|гм|km|dm|cm|mm)([32]|³|²)(\s|\.|\!|\?|\,|$|\±\;|\;|\<)/iue' + ), + 'replacement' => array( + '\1\2 \4\5', + '$m[1].$m[2]." ".$m[4].($m[5]=="3"||$m[5]=="2"? "&sup".$m[5].";" : $m[5] ).$m[6]' + ), + ), + 'nbsp_before_weight_unit' => array( + 'description' => 'Замена символов и привязка сокращений в весовых величинах: г, кг, мг…', + 'pattern' => '/(\s|^|\>|\ \;|\,)(\d+)( |\ \;)?(г|кг|мг|т)(\s|\.|\!|\?|\,|$|\ \;|\;)/iu', + 'replacement' => '\1\2 \4\5', + ), + 'nobr_before_unit_volt' => array( + 'description' => 'Установка пробельных символов в сокращении вольт', + 'pattern' => '/(\d+)([вВ]| В)(\s|\.|\!|\?|\,|$)/u', + 'replacement' => '\1 В\3' + ), + 'ps_pps' => array( + 'description' => 'Объединение сокращений P.S., P.P.S.', + 'pattern' => '/(^|\040|\t|\>|\r|\n)(p\.\040?)(p\.\040?)?(s\.)([^\<])/ie', + 'replacement' => '$m[1] . $this->tag(trim($m[2]) . " " . ($m[3] ? trim($m[3]) . " " : ""). $m[4], "span", array("class" => "nowrap") ).$m[5] ' + ), + 'nobr_vtch_itd_itp' => array( + 'description' => 'Объединение сокращений и т.д., и т.п., в т.ч.', + 'cycled' => true, + 'pattern' => array( + '/(^|\s|\ \;)и( |\ \;)т\.?[ ]?д(\.|$|\s|\ \;)/ue', + '/(^|\s|\ \;)и( |\ \;)т\.?[ ]?п(\.|$|\s|\ \;)/ue', + '/(^|\s|\ \;)в( |\ \;)т\.?[ ]?ч(\.|$|\s|\ \;)/ue', + ), + 'replacement' => array( + '$m[1].$this->tag("и т. д.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', + '$m[1].$this->tag("и т. п.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', + '$m[1].$this->tag("в т. ч.", "span", array("class" => "nowrap")).($m[3]!="."? $m[3] : "" )', + ) + ), + 'nbsp_te' => array( + 'description' => 'Обработка т.е.', + 'pattern' => '/(^|\s|\ \;)([тТ])\.?[ ]?е\./ue', + 'replacement' => '$m[1].$this->tag($m[2].". е.", "span", array("class" => "nowrap"))', + ), + 'nbsp_money_abbr' => array( + 'description' => 'Форматирование денежных сокращений (расстановка пробелов и привязка названия валюты к числу)', + 'pattern' => '/(\d)((\040|\ \;)?(тыс|млн|млрд)\.?(\040|\ \;)?)?(\040|\ \;)?(руб\.|долл\.|евро|€|€|\$|у[\.]? ?е[\.]?)/ieu', + 'replacement' => '$m[1].($m[4]?" ".$m[4].($m[4]=="тыс"?".":""):"")." ".(!preg_match("#у[\\\\.]? ?е[\\\\.]?#iu",$m[7])?$m[7]:"у.е.")', + ), + 'nbsp_money_abbr_rev' => array( + 'description' => 'Привязка валюты к числу спереди', + 'pattern' => '/(€|€|\$)\s?(\d)/iu', + 'replacement' => '\1 \2' + ), + 'nbsp_org_abbr' => array( + 'description' => 'Привязка сокращений форм собственности к названиям организаций', + 'pattern' => '/([^a-zA-Zа-яёА-ЯЁ]|^)(ООО|ЗАО|ОАО|НИИ|ПБОЮЛ) ([a-zA-Zа-яёА-ЯЁ]|\"|\«\;|\&bdquo\;|<)/u', + 'replacement' => '\1\2 \3' + ), + 'nobr_gost' => array( + 'description' => 'Привязка сокращения ГОСТ к номеру', + 'pattern' => array( + '/(\040|\t|\ \;|^)ГОСТ( |\ \;)?(\d+)((\-|\&minus\;|\&mdash\;)(\d+))?(( |\ \;)(\-|\&mdash\;))?/ieu', + '/(\040|\t|\ \;|^|\>)ГОСТ( |\ \;)?(\d+)(\-|\&minus\;|\&mdash\;)(\d+)/ieu', + ), + 'replacement' => array( + '$m[1].$this->tag("ГОСТ ".$m[3].(isset($m[6])?"–".$m[6]:"").(isset($m[7])?" —":""),"span", array("class"=>"nowrap"))', + '$m[1]."ГОСТ ".$m[3]."–".$m[5]', + ), + ), + /* + 'nobr_vtch_itd_itp' => array( + 'description' => 'Привязка сокращений до н.э., н.э.', + 'pattern' => array( + + //IV в до н.э, в V-VIвв до нэ., третий в. н.э. + + '/(\s|\ \;)и( |\ \;)т\.?[ ]?д\./ue', + '/(\s|\ \;)и( |\ \;)т\.?[ ]?п\./ue', + '/(\s|\ \;)в( |\ \;)т\.?[ ]?ч\./ue', + ), + 'replacement' => array( + '$m[1].$this->tag("и т. д.", "span", array("class" => "nowrap"))', + '$m[1].$this->tag("и т. п.", "span", array("class" => "nowrap"))', + '$m[1].$this->tag("в т. ч.", "span", array("class" => "nowrap"))', + ) + ), + */ + + + ); +} + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Dash extends EMT_Tret +{ + public $title = "Дефисы и тире"; + public $rules = array( + 'mdash_symbol_to_html_mdash' => array( + 'description' => 'Замена символа тире на html конструкцию', + 'pattern' => '/—/iu', + 'replacement' => '—' + ), + 'mdash' => array( + 'description' => 'Тире после кавычек, скобочек, пунктуации', + 'pattern' => array( + '/([a-zа-яё0-9]+|\,|\:|\)|\&(ra|ld)quo\;|\|\"|\>)(\040|\t)(—|\-|\&mdash\;)(\s|$|\<)/ui', + '/(\,|\:|\)|\")(—|\-|\&mdash\;)(\s|$|\<)/ui', + ), + 'replacement' => array( + '\1 —\5', + '\1 —\3', + ), + ), + 'mdash_2' => array( + 'description' => 'Тире после переноса строки', + 'pattern' => '/(\n|\r|^|\>)(\-|\&mdash\;)(\t|\040)/', + 'replacement' => '\1— ' + ), + 'mdash_3' => array( + 'description' => 'Тире после знаков восклицания, троеточия и прочее', + 'pattern' => '/(\.|\!|\?|\&hellip\;)(\040|\t|\ \;)(\-|\&mdash\;)(\040|\t|\ \;)/', + 'replacement' => '\1 — ' + ), + 'iz_za_pod' => array( + 'description' => 'Расстановка дефисов между из-за, из-под', + 'pattern' => '/(\s|\ \;|\>|^)(из)(\040|\t|\ \;)\-?(за|под)([\.\,\!\?\:\;]|\040|\ \;)/uie', + 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' + ), + 'to_libo_nibud' => array( + 'description' => 'Автоматическая простановка дефисов в обезличенных местоимениях и междометиях', + 'cycled' => true, + 'pattern' => '/(\s|^|\ \;|\>)(кто|кем|когда|зачем|почему|как|что|чем|где|чего|кого)\-?(\040|\t|\ \;)\-?(то|либо|нибудь)([\.\,\!\?\;]|\040|\ \;|$)/uie', + 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' + ), + 'koe_kak' => array( + 'description' => 'Кое-как, кой-кого, все-таки', + 'cycled' => true, + 'pattern' => array( + '/(\s|^|\ \;|\>)(кое)\-?(\040|\t|\ \;)\-?(как)([\.\,\!\?\;]|\040|\ \;|$)/uie', + '/(\s|^|\ \;|\>)(кой)\-?(\040|\t|\ \;)\-?(кого)([\.\,\!\?\;]|\040|\ \;|$)/uie', + '/(\s|^|\ \;|\>)(вс[её])\-?(\040|\t|\ \;)\-?(таки)([\.\,\!\?\;]|\040|\ \;|$)/uie', + ), + 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' + ), + 'ka_de_kas' => array( + 'description' => 'Расстановка дефисов с частицами ка, де, кась', + 'disabled' => true, + 'pattern' => array( + '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(ка)([\.\,\!\?\;]|\040|\ \;|$)/uie', + '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(де)([\.\,\!\?\;]|\040|\ \;|$)/uie', + '/(\s|^|\ \;|\>)([а-яё]+)(\040|\t|\ \;)(кась)([\.\,\!\?\;]|\040|\ \;|$)/uie', + ), + 'replacement' => '($m[1] == " " ? " " : $m[1]) . $m[2]."-".$m[4] . ($m[5] == " "? " " : $m[5])' + ), + + + + ); + +} + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Date extends EMT_Tret +{ + public $title = "Даты и дни"; + + public $classes = array( + 'nowrap' => 'word-spacing:nowrap;', + ); + + public $rules = array( + 'years' => array( + 'description' => 'Установка тире и пробельных символов в периодах дат', + 'pattern' => '/(с|по|период|середины|начала|начало|конца|конец|половины|в|между|\([cс]\)|\©\;)(\s+|\ \;)([\d]{4})(-|\&mdash\;|\&minus\;)([\d]{4})(( |\ \;)?(г\.г\.|гг\.|гг|г\.|г)([^а-яёa-z]))?/eui', + 'replacement' => '$m[1].$m[2]. (intval($m[3])>=intval($m[5])? $m[3].$m[4].$m[5] : $m[3]."—".$m[5]) . (isset($m[6])? " гг.":"").(isset($m[9])?$m[9]:"")' + ), + 'mdash_month_interval' => array( + 'description' => 'Расстановка тире и объединение в неразрывные периоды месяцев', + 'disabled' => true, + 'pattern' => '/((январ|феврал|сентябр|октябр|ноябр|декабр)([ьяюе]|[её]м)|(апрел|июн|июл)([ьяюе]|ем)|(март|август)([ауе]|ом)?|ма[йяюе]|маем)\-((январ|феврал|сентябр|октябр|ноябр|декабр)([ьяюе]|[её]м)|(апрел|июн|июл)([ьяюе]|ем)|(март|август)([ауе]|ом)?|ма[йяюе]|маем)/iu', + 'replacement' => '\1—\8' + ), + 'nbsp_and_dash_month_interval' => array( + 'description' => 'Расстановка тире и объединение в неразрывные периоды дней', + 'disabled' => true, + 'pattern' => '/([^\>]|^)(\d+)(\-|\&minus\;|\&mdash\;)(\d+)( |\ \;)(января|февраля|марта|апреля|мая|июня|июля|августа|сентября|октября|ноября|декабря)([^\<]|$)/ieu', + 'replacement' => '$m[1].$this->tag($m[2]."—".$m[4]." ".$m[6],"span", array("class"=>"nowrap")).$m[7]' + ), + 'nobr_year_in_date' => array( + 'description' => 'Привязка года к дате', + 'pattern' => array( + '/(\s|\ \;)([0-9]{2}\.[0-9]{2}\.([0-9]{2})?[0-9]{2})(\s|\ \;)?г(\.|\s|\ \;)/eiu', + '/(\s|\ \;)([0-9]{2}\.[0-9]{2}\.([0-9]{2})?[0-9]{2})(\s|\ \;|\.(\s|\ \;|$)|$)/eiu', + ), + 'replacement' => array( + '$m[1].$this->tag($m[2]." г.","span", array("class"=>"nowrap")).($m[5]==="."?"":" ")', + '$m[1].$this->tag($m[2],"span", array("class"=>"nowrap")).$m[4]', + ), + ), + 'space_posle_goda' => array( + 'description' => 'Пробел после года', + 'pattern' => '/(^|\040|\ \;)([0-9]{3,4})(год([ауе]|ом)?)([^a-zа-яё]|$)/ui', + 'replacement' => '\1\2 \3\5' + ), + 'nbsp_posle_goda_abbr' => array( + 'description' => 'Пробел после года', + 'pattern' => '/(^|\040|\ \;|\"|\«\;)([0-9]{3,4})[ ]?(г\.)([^a-zа-яё]|$)/ui', + 'replacement' => '\1\2 \3\4' + ), + + ); +} + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Etc extends EMT_Tret +{ + + + public $classes = array( + 'nowrap' => 'word-spacing:nowrap;', + ); + + + /** + * Базовые параметры тофа + * + * @var array + */ + public $title = "Прочее"; + public $rules = array( + 'acute_accent' => array( + 'description' => 'Акцент', + 'pattern' => '/(у|е|ы|а|о|э|я|и|ю|ё)\`(\w)/i', + 'replacement' => '\1́\2' + ), + + + + 'word_sup' => array( + 'description' => 'Надстрочный текст после символа ^', + 'pattern' => '/((\s|\ \;|^)+)\^([a-zа-яё0-9\.\:\,\-]+)(\s|\ \;|$|\.$)/ieu', + 'replacement' => '"" . $this->tag($this->tag($m[3],"small"),"sup") . $m[4]' + ), + 'century_period' => array( + 'description' => 'Тире между диапозоном веков', + 'pattern' => '/(\040|\t|\ \;|^)([XIV]{1,5})(-|\&mdash\;)([XIV]{1,5})(( |\ \;)?(в\.в\.|вв\.|вв|в\.|в))/eu', + 'replacement' => '$m[1] .$this->tag($m[2]."—".$m[4]." вв.","span", array("class"=>"nowrap"))' + ), + 'time_interval' => array( + 'description' => 'Тире и отмена переноса между диапозоном времени', + 'pattern' => '/([^\d\>]|^)([\d]{1,2}\:[\d]{2})(-|\&mdash\;|\&minus\;)([\d]{1,2}\:[\d]{2})([^\d\<]|$)/eui', + 'replacement' => '$m[1] . $this->tag($m[2]."—".$m[4],"span", array("class"=>"nowrap")).$m[5]' + ), + 'split_number_to_triads' => array( + 'description' => 'Разбиение числа на триады', + 'pattern' => '/([^a-zA-Z0-9<\)]|^)([0-9]{5,})([^a-zA-Z>\(]|$)/eu', + 'replacement' => '$m[1].str_replace(" "," ",EMT_Lib::split_number($m[2])).$m[3] ' + //'function' => 'split_number' + ), + 'expand_no_nbsp_in_nobr' => array( + 'description' => 'Удаление nbsp в nobr/nowrap тэгах', + 'function' => 'remove_nbsp' + ), + 'nobr_to_nbsp' => array( + 'description' => 'Преобразование nobr в nbsp', + 'disabled' => true, + 'function' => 'nobr_to_nbsp' + ), + ); + + protected function remove_nbsp() + { + $thetag = $this->tag("###", 'span', array('class' => "nowrap")); + $arr = explode("###", $thetag); + $b = preg_quote($arr[0], '/'); + $e = preg_quote($arr[1], '/'); + + $match = '/(^|[^a-zа-яё])([a-zа-яё]+)\ \;('.$b.')/iu'; + do { + $this->_text = preg_replace($match, '\1\3\2 ', $this->_text); + } while(preg_match($match, $this->_text)); + + $match = '/('.$e.')\ \;([a-zа-яё]+)($|[^a-zа-яё])/iu'; + do { + $this->_text = preg_replace($match, ' \2\1\3', $this->_text); + } while(preg_match($match, $this->_text)); + + $this->_text = $this->preg_replace_e('/'.$b.'.*?'.$e.'/iue', 'str_replace(" "," ",$m[0]);' , $this->_text ); + } + + protected function nobr_to_nbsp() + { + $thetag = $this->tag("###", 'span', array('class' => "nowrap")); + $arr = explode("###", $thetag); + $b = preg_quote($arr[0], '/'); + $e = preg_quote($arr[1], '/'); + $this->_text = $this->preg_replace_e('/'.$b.'(.*?)'.$e.'/iue', 'str_replace(" "," ",$m[1]);' , $this->_text ); + } + /* + protected function split_number () { + + $this->preg_replace_e("/([^a-zA-Z<]|^)([0-9]{5,})([^a-zA-Z>]|$)/u", ) + + $match = ; + while(preg_match($match, $this->_text, $m)) { + $repl = ""; + for($i = strlen($m[2]); $i >=0 ; $i-=3) + if($i-3>=0) $repl = ($i>3?" ":"").substr($m[2], $i-3, 3) . $repl; else $repl = substr($m[2], 0, $i) . $repl; + $this->_text = str_replace($m[1], $repl, $this->_text); + } + }*/ + +} + + + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Nobr extends EMT_Tret +{ + public $title = "Неразрывные конструкции"; + + public $classes = array( + 'nowrap' => 'word-spacing:nowrap;', + ); + + public $rules = array( + + 'super_nbsp' => array( + 'description' => 'Привязка союзов и предлогов к написанным после словам', + 'pattern' => '/(\s|^|\&(la|bd)quo\;|\>|\(|\&mdash\;\ \;)([a-zа-яё]{1,2}\s+)([a-zа-яё]{1,2}\s+)?([a-zа-яё0-9\-]{2,}|[0-9])/ieu', + 'replacement' => '$m[1] . trim($m[3]) . " " . ($m[4] ? trim($m[4]) . " " : "") . $m[5]' + ), + 'nbsp_in_the_end' => array( + 'description' => 'Привязка союзов и предлогов к предыдущим словам в случае конца предложения', + 'pattern' => '/([a-zа-яё0-9\-]{3,}) ([a-zа-яё]{1,2})\.( [A-ZА-ЯЁ]|$)/u', + 'replacement' => '\1 \2.\3' + ), + 'phone_builder' => array( + 'description' => 'Объединение в неразрывные конструкции номеров телефонов', + 'pattern' => + array( + '/([^\d\+]|^)([\+]?[0-9]{1,3})( |\ \;|\&thinsp\;)([0-9]{3,4}|\([0-9]{3,4}\))( |\ \;|\&thinsp\;)([0-9]{2,3})(-|\&minus\;)([0-9]{2})(-|\&minus\;)([0-9]{2})([^\d]|$)/e', + '/([^\d\+]|^)([\+]?[0-9]{1,3})( |\ \;|\&thinsp\;)([0-9]{3,4}|[0-9]{3,4})( |\ \;|\&thinsp\;)([0-9]{2,3})(-|\&minus\;)([0-9]{2})(-|\&minus\;)([0-9]{2})([^\d]|$)/e', + ), + 'replacement' => + array( + '$m[1] .(($m[1] == ">" || $m[11] == "<") ? $m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10] :$this->tag($m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10], "span", array("class"=>"nowrap")) ).$m[11]', + '$m[1] .(($m[1] == ">" || $m[11] == "<") ? $m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10] :$this->tag($m[2]." ".$m[4]." ".$m[6]."-".$m[8]."-".$m[10], "span", array("class"=>"nowrap")) ).$m[11]', + ), + ), + 'phone_builder_v2' => array( + 'description' => 'Дополнительный формат номеров телефонов', + 'pattern' => '/([^\d]|^)\+\s?([0-9]{1})\s?\(([0-9]{3,4})\)\s?(\d{3})(\d{2})(\d{2})([^\d]|$)/ie', + 'replacement' => '$m[1].$this->tag("+".$m[2]." ".$m[3]." ".$m[4]."-".$m[5]."-".$m[6], "span", array("class" => "nowrap")).$m[7]', + ), + 'ip_address' => array( + 'description' => 'Объединение IP-адресов', + 'pattern' => '/(\s|\ \;|^)(\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3})/ie', + 'replacement' => '$m[1] . $this->nowrap_ip_address($m[2])' + ), + 'dots_for_surname_abbr' => array( + 'disabled' => true, + 'description' => 'Простановка точек к инициалам у фамилии', + 'pattern' => + array( + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])\.?(\s|\ \;)?([А-ЯЁ])(\s|\ \;)([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])\.?(\s|\ \;)?([А-ЯЁ])\.?(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + ), + 'replacement' => + array( + '$m[1].$this->tag($m[2].". ".$m[4].". ".$m[6], "span", array("class" => "nowrap")).$m[7]', + '$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', + ), + ), + 'spaces_nobr_in_surname_abbr' => array( + 'description' => 'Привязка инициалов к фамилиям', + 'pattern' => + array( + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])\.(\s|\ \;)?([А-ЯЁ])\.(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ])(\s|\ \;)?([А-ЯЁ])(\s|\ \;)([А-ЯЁ][а-яё]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + '/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([А-ЯЁ][а-яё]+)(\s|\ \;)([А-ЯЁ])(\s|\ \;)?([А-ЯЁ])(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + //'/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([A-Z])\.?(\s|\ \;)?([A-Z])(\.(\s|\ \;)?|(\s|\ \;))([A-Z][a-z]+)(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + //'/(\s|^|\.|\,|\;|\:|\?|\!|\ \;)([A-Z][a-z]+)(\s|\ \;)([A-Z])\.?(\s|\ \;)?([A-Z])\.?(\s|$|\.|\,|\;|\:|\?|\!|\ \;)/ue', + ), + 'replacement' => + array( + '$m[1].$this->tag($m[2].". ".$m[4].". ".$m[6], "span", array("class" => "nowrap")).$m[7]', + '$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', + '$m[1].$this->tag($m[2].(isset($m[3])? " " : "" ).$m[4].(isset($m[5])? " " : "" ).$m[6], "span", array("class" => "nowrap")).$m[7]', + '$m[1].$this->tag($m[2]." ".$m[4].(isset($m[5])? " " : "" ).$m[6], "span", array("class" => "nowrap")).$m[7]', + //'$m[1].$this->tag($m[2].". ".$m[4].". ".$m[8], "span", array("class" => "nowrap")).$m[9]', + //'$m[1].$this->tag($m[2]." ".$m[4].". ".$m[6].".", "span", array("class" => "nowrap")).$m[7]', + ), + ), + 'nbsp_before_particle' => array( + 'description' => 'Неразрывный пробел перед частицей', + 'pattern' => '/(\040|\t)+(ли|бы|б|же|ж)(\ \;|\.|\,|\:|\;|\&hellip\;|\?|\s)/iue', + 'replacement' => '" ".$m[2] . ($m[3] == " " ? " " : $m[3])' + ), + 'nbsp_v_kak_to' => array( + 'description' => 'Неразрывный пробел в как то', + 'pattern' => '/как то\:/ui', + 'replacement' => 'как то:' + ), + 'nbsp_celcius' => array( + 'description' => 'Привязка градусов к числу', + 'pattern' => '/(\s|^|\>|\ \;)(\d+)( |\ \;)?(°|\°\;)(C|С)(\s|\.|\!|\?|\,|$|\ \;|\;)/iu', + 'replacement' => '\1\2 \4C\6' + ), + 'hyphen_nowrap_in_small_words' => array( + 'description' => 'Обрамление пятисимвольных слов разделенных дефисом в неразрывные блоки', + 'disabled' => true, + 'cycled' => true, + 'pattern' => '/(\ \;|\s|\>|^)([a-zа-яё]{1}\-[a-zа-яё]{4}|[a-zа-яё]{2}\-[a-zа-яё]{3}|[a-zа-яё]{3}\-[a-zа-яё]{2}|[a-zа-яё]{4}\-[a-zа-яё]{1}|когда\-то|кое\-как|кой\-кого|вс[её]\-таки|[а-яё]+\-(кась|ка|де))(\s|\.|\,|\!|\?|\ \;|\&hellip\;|$)/uie', + 'replacement' => '$m[1] . $this->tag($m[2], "span", array("class"=>"nowrap")) . $m[4]', + ), + 'hyphen_nowrap' => array( + 'description' => 'Отмена переноса слова с дефисом', + 'disabled' => true, + 'cycled' => true, + 'pattern' => '/(\ \;|\s|\>|^)([a-zа-яё]+)((\-([a-zа-яё]+)){1,2})(\s|\.|\,|\!|\?|\ \;|\&hellip\;|$)/uie', + 'replacement' => '$m[1] . $this->tag($m[2].$m[3], "span", array("class"=>"nowrap")) . $m[6]' + ), + ); + + /** + * Объединение IP-адрессов в неразрывные конструкции (IPv4 only) + * + * @param unknown_type $triads + * @return unknown + */ + protected function nowrap_ip_address($triads) + { + $triad = explode('.', $triads); + $addTag = true; + + foreach ($triad as $value) { + $value = (int) $value; + if ($value > 255) { + $addTag = false; + break; + } + } + + if (true === $addTag) { + $triads = $this->tag($triads, 'span', array('class' => "nowrap")); + } + + return $triads; + } +} + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_Number extends EMT_Tret +{ + public $title = "Числа, дроби, математические знаки"; + + + public $rules = array( + 'minus_between_nums' => array( + 'description' => 'Расстановка знака минус между числами', + 'pattern' => '/(\d+)\-(\d)/i', + 'replacement' => '\1−\2' + ), + 'minus_in_numbers_range' => array( + 'description' => 'Расстановка знака минус между диапозоном чисел', + 'pattern' => '/(^|\s|\ \;)(\&minus\;|\-)(\d+)(\.\.\.|\&hellip\;)(\s|\ \;)?(\+|\-|\&minus\;)?(\d+)/ie', + 'replacement' => '$m[1] ."−".$m[3] . $m[4].$m[5].($m[6]=="+"?$m[6]:"−").$m[7]' + ), + 'auto_times_x' => array( + 'description' => 'Замена x на символ × в размерных единицах', + 'cycled' => true, + 'pattern' => '/([^a-zA-Z><]|^)(\×\;)?(\d+)(\040*)(x|х)(\040*)(\d+)([^a-zA-Z><]|$)/u', + 'replacement' => '\1\2\3×\7\8' + ), + 'numeric_sub' => array( + 'description' => 'Нижний индекс', + 'pattern' => '/([a-zа-яё0-9])\_([\d]{1,3})([^@а-яёa-z0-9]|$)/ieu', + 'replacement' => '$m[1] . $this->tag($this->tag($m[2],"small"),"sub") . $m[3]' + ), + 'numeric_sup' => array( + 'description' => 'Верхний индекс', + 'pattern' => '/([a-zа-яё0-9])\^([\d]{1,3})([^а-яёa-z0-9]|$)/ieu', + 'replacement' => '$m[1] . $this->tag($this->tag($m[2],"small"),"sup") . $m[3]' + ), + 'simple_fraction' => array( + 'description' => 'Замена дробей 1/2, 1/4, 3/4 на соответствующие символы', + 'pattern' => array('/(^|\D)1\/(2|4)(\D)/', '/(^|\D)3\/4(\D)/'), + 'replacement' => array('\1&frac1\2;\3', '\1¾\2') + ), + 'math_chars' => array( + 'description' => 'Математические знаки больше/меньше/плюс минус/неравно', + 'pattern' => array('/!=/', '/\<=/', '/([^=]|^)\>=/', '/~=/', '/\+-/'), + 'replacement' => array('≠', '≤', '\1≥', '≅', '±' ) + ), + + 'thinsp_between_number_triads' => array( + 'description' => 'Объединение триад чисел полупробелом', + 'pattern' => '/([0-9]{1,3}( [0-9]{3}){1,})(.|$)/ue', + 'replacement' => '($m[3]=="-"? $m[0]:str_replace(" "," ",$m[1]).$m[3])' + ), + 'thinsp_between_no_and_number' => array( + 'description' => 'Пробел между симоволом номера и числом', + 'pattern' => '/(№|\№\;)(\s| )*(\d)/iu', + 'replacement' => '№ \3' + ), + 'thinsp_between_sect_and_number' => array( + 'description' => 'Пробел между параграфом и числом', + 'pattern' => '/(§|\§\;)(\s| )*(\d+|[IVX]+|[a-zа-яё]+)/ui', + 'replacement' => '§ \3' + ), + ); +} + + +/** + * @see EMT_Tret + */ + +class EMT_Tret_OptAlign extends EMT_Tret +{ + + public $classes = array( + 'oa_obracket_sp_s' => "margin-right:0.3em;", + "oa_obracket_sp_b" => "margin-left:-0.3em;", + "oa_obracket_nl_b" => "margin-left:-0.3em;", + "oa_comma_b" => "margin-right:-0.2em;", + "oa_comma_e" => "margin-left:0.2em;", + 'oa_oquote_nl' => "margin-left:-0.44em;", + 'oa_oqoute_sp_s' => "margin-right:0.44em;", + 'oa_oqoute_sp_q' => "margin-left:-0.44em;", + ); + + /** + * Базовые параметры тофа + * + * @var array + */ + public $title = "Оптическое выравнивание"; + public $rules = array( + 'oa_oquote' => array( + 'description' => 'Оптическое выравнивание открывающей кавычки', + //'disabled' => true, + 'pattern' => array( + '/([a-zа-яё\-]{3,})(\040|\ \;|\t)(\«\;)/uie', + '/(\n|\r|^)(\«\;)/ei' + ), + 'replacement' => array( + '$m[1] . $this->tag($m[2], "span", array("class"=>"oa_oqoute_sp_s")) . $this->tag($m[3], "span", array("class"=>"oa_oqoute_sp_q"))', + '$m[1] . $this->tag($m[2], "span", array("class"=>"oa_oquote_nl"))', + ), + ), + 'oa_oquote_extra' => array( + 'description' => 'Оптическое выравнивание кавычки', + //'disabled' => true, + 'function' => 'oaquote_extra' + ), + 'oa_obracket_coma' => array( + 'description' => 'Оптическое выравнивание для пунктуации (скобка)', + //'disabled' => true, + 'pattern' => array( + '/(\040|\ \;|\t)\(/ei', + '/(\n|\r|^)\(/ei', + //'/([а-яёa-z0-9]+)\,(\040+)/iue', + ), + 'replacement' => array( + '$this->tag($m[1], "span", array("class"=>"oa_obracket_sp_s")) . $this->tag("(", "span", array("class"=>"oa_obracket_sp_b"))', + '$m[1] . $this->tag("(", "span", array("class"=>"oa_obracket_nl_b"))', + //'$m[1] . $this->tag(",", "span", array("class"=>"oa_comma_b")) . $this->tag(" ", "span", array("class"=>"oa_comma_e"))', + ), + ), + + ); + + /** + * Если стоит открывающая кавычка после