<?php

defined('HOSTCMS') || exit('HostCMS: access denied.');

/**
 * String helper
 *
 * @package HostCMS 6\Core
 * @version 6.x
 * @author Hostmake LLC
 * @copyright © 2005-2013 ООО "Хостмэйк" (Hostmake LLC), http://www.hostcms.ru
 */
class Core_Str
{
	/**
	 * List of illegal characters
	 * @var array
	 */
	static protected $_xmlIllegalCharacters = NULL;

	/**
	 * Get XML illegal characters
	 * @return array
	 */
	static public function getXmlIllegalCharacters()
	{
		if (is_null(self::$_xmlIllegalCharacters))
		{
			$aTmp = array(
				chr(0x00), chr(0x01), chr(0x02), chr(0x03), chr(0x04), chr(0x05), chr(0x06), chr(0x07), chr(0x08),
				/*chr(0x09), chr(0x0A,*/ chr(0x0B), chr(0x0C), /*chr(0x0D,*/ chr(0x0E), chr(0x0F),
				chr(0x10), chr(0x11), chr(0x12), chr(0x13), chr(0x14), chr(0x15), chr(0x16), chr(0x17), chr(0x18),
				chr(0x19), chr(0x1A), chr(0x1B), chr(0x1C), chr(0x1D), chr(0x1E), chr(0x1F)
			);

			self::$_xmlIllegalCharacters = array_combine($aTmp, array_fill_keys(array_keys($aTmp), ''));
		}

		return self::$_xmlIllegalCharacters;
	}

	/**
	 * Correct string to XML legal characters
	 * http://www.w3.org/TR/xml/#charsets
	 * @param string $string
	 * @return string
	 */
	static public function xml($string)
	{
		return htmlspecialchars(
			self::deleteIllegalCharacters($string)
		);
	}

	/**
	 * Delete illegal characters
	 * @param string $string
	 * @return string
	 */
	static public function deleteIllegalCharacters($string)
	{
		$string = strtr($string, self::getXmlIllegalCharacters());
		return iconv("UTF-8", "UTF-8//IGNORE//TRANSLIT",
			//str_replace(self::getXmlIllegalCharacters(), '', $string)
			$string
		);
	}

	/**
	 * Cut string to defined lenght
	 * @param string $string source string
	 * @param int $maxLen lenght
	 * @return string
	 */
	static public function cut($string, $maxLen = 15)
	{
		if (mb_strlen($string) > $maxLen)
		{
			$maxLen < 15 && $maxLen = 15;
			$string = mb_substr($string, 0, $maxLen - 10) . '…' . mb_substr($string, -7);
		}

		return $string;
	}

	/**
	 * Cut length of words in a string
	 * @param string $string source string
	 * @param int $maxLen word lenght
	 * @return string
	 */
	static public function cutWords($string, $maxLen)
	{
		$string = trim($string);

		if (mb_strlen($string) > 0)
		{
			$aString = explode(' ', $string);

			if (count($aString) > 0)
			{
				foreach ($aString as $key => $value)
				{
					if (mb_strlen($value) > $maxLen)
					{
						$aString[$key] = self::cut($value, $maxLen);
					}
				}
			}

			$string = implode(' ', $aString);
		}

		return $string;
	}

	/**
	 * Укорачивает описание до заданного количества символов, оставляя целое число предложений
	 *
	 * @param string $text - text
	 * @param int $maxLen - max ken
	 * <code>
	 * <?php
	 * $text = 'Текст описания, который необходимо укоротить';
	 * $maxLen = 20;
	 * $cutText = Core_Str::cutSentences($text, $maxLen);
	 *
	 * // Распечатаем результат
	 * echo $cutText;
	 * ?>
	 * </code>
	 * @return string
	 */
	static public function cutSentences($text, $maxLen = 255)
	{
		$lenght = mb_strlen(strval($text));
		$maxLen = intval($maxLen);

		if ($lenght > $maxLen)
		{
			$text = mb_substr($text, 0, $maxLen);

			$last_point = mb_strrpos($text, '. ');

			$text = $last_point === FALSE
				? mb_substr($text, 0, mb_strrpos($text, ' '))
				: mb_substr($text, 0, $last_point + 1);
		}

		return $text;
	}

	/**
	 * Translation from russian to english
	 * @param string $string source string
	 * @return string
	 */
	static public function translate($string)
	{
		$url = 'http://translate.yandex.net/api/v1/tr.json/translate?lang=ru-en&text=' . urlencode($string);

		$Core_Http = Core_Http::instance()
			->url($url)
			->timeout(3)
			->execute();

		$data = trim($Core_Http->getBody());

		if (strlen($data))
		{
			$oData = json_decode($data);

			if (is_object($oData) && $oData->code == 200 && isset($oData->text[0]))
			{
				return $oData->text[0];
			}
		}

		return NULL;
	}

	/**
	 * Transliteration
	 * @param string $string source string
	 * @return string
	 */
	static public function transliteration($string)
	{
		$string = mb_strtolower(trim(strval($string)));

		$spaceSeparator = '-';

		// Умляуты и другие кодировки
		$uml_search = array('À','Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'ĸ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ŉ', 'Ŋ', 'ŋ', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'Ǆ', 'ǅ', 'ǆ', 'Ǉ', 'ǈ', 'ǉ', 'Ǌ', 'ǋ', 'ǌ', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'ǝ', 'Ǟ', 'ǟ', 'Ǡ', 'ǡ', 'Ǣ', 'ǣ', 'Ǥ', 'ǥ', 'Ǧ', 'ǧ', 'Ǩ', 'ǩ', 'Ǫ', 'ǫ', 'Ǭ', 'ǭ', 'Ǯ', 'ǯ', 'ǰ', 'Ǳ', 'ǲ', 'ǳ', 'Ǵ', 'ǵ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ', 'Ȁ', 'ȁ', 'Ȃ', 'ȃ', 'Ȅ', 'ґ', 'є',  'і', 'ї',  'Ґ', 'Є',  'І', 'Ї', 'ô');

		$uml_replace = array('a','a','a','a','a','a','ae','c','e','e','e','e','i','i','i','i','d','n','o','o','o','o','o','o','u','u','u','u','y','ss','a','a','a','a','a','a','ae','c','e','e','e','e','i','i','i','i','d','n','o','o','o','o','o','o','u','u','u','u','y','y','a','a','a','a','a','a','c','c','c','c','c','c','c','c','d','d','d','d','e','e','e','e','e','e','e','e','e','e','g','g','g','g','g','g','g','g','h','h','h','i','i','i','i','i','i','i','i','i','i','j','j','k','k','k','l','l','l','l','l','l','l','l','l','l','n','n','n','n','n','n','n','n','n','o','o','o','o','o','o','ce','ce','r','r','r','r','r','r','s','s','s','s','s','s','s','s','t','t','t','t','t','t','u','u','u','u','u','u','u','u','u','u','u','u','w','w','y','y','y','z','z','z','z','z','z','dz','dz','dz','lj','lj','kj','nj','nj','nj','a','a','i','i','o','o','u','u','u','u','u','u','u','u','u','u','e','a','a','a','a','ae','ae','g','g','g','g','k','k','o','o','o','o','z','z','z','dz','dz','dz','g','g','a','a','ae','ae','o','o','a','a','a','a','e','g', 'ye', 'i', 'yi', 'G', 'Ye', 'I', 'I', 'o');

		$string = str_replace($uml_search, $uml_replace, $string);

		// для малых
		$search  = array(' ', 'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й' ,'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ч', 'ц', 'ш', 'щ',  'ъ', 'ы', 'ь', 'э', 'ю', 'я');

		// для больших
		$search2 = array(' ', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й' ,'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ч', 'Ц', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я');

		// замена
		$replace = array($spaceSeparator, 'a', 'b', 'v', 'g', 'd', 'e', 'e', 'zh', 'z', 'i', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'kh', 'ch', 'ts', 'sh', 'shch', '', 'y', '', 'e', 'iu', 'ia');

		// малые
		$string = str_replace($search, $replace, $string);

		// большие
		$string = str_replace($search2, $replace, $string);

		$string = preg_replace('/[^a-zA-Z0-9\-_]/u', '', $string);

		// Двойные $spaceSeparator заменяем на один
		while (mb_strpos($string, $spaceSeparator . $spaceSeparator) !== FALSE)
		{
			$string = str_replace($spaceSeparator . $spaceSeparator, $spaceSeparator, $string);
		}

		return $string;
	}

	/**
	 * Convert HTML entity to numeric character reference (NCR)
	 * @param string $str source string
	 * @return string
	 */
	static public function str2ncr($str)
	{
		$aEntities = array(
			'&amp;nbsp;', '&amp;iexcl;', '&amp;cent;', '&amp;pound;', '&amp;curren;', '&amp;yen;', '&amp;brvbar;', '&amp;sect;', '&amp;uml;', '&amp;copy;', '&amp;ordf;', '&amp;laquo;', '&amp;not;', '&amp;shy;', '&amp;reg;', '&amp;macr;', '&amp;deg;', '&amp;plusmn;', '&amp;sup2;', '&amp;sup3;', '&amp;acute;', '&amp;micro;', '&amp;para;', '&amp;middot;', '&amp;cedil;', '&amp;sup1;', '&amp;ordm;', '&amp;raquo;', '&amp;frac14;', '&amp;frac12;', '&amp;frac34;', '&amp;iquest;', '&amp;agrave;', '&amp;aacute;', '&amp;acirc;', '&amp;atilde;', '&amp;auml;', '&amp;aring;', '&amp;aelig;', '&amp;ccedil;', '&amp;egrave;', '&amp;eacute;', '&amp;ecirc;', '&amp;euml;', '&amp;igrave;', '&amp;iacute;', '&amp;icirc;', '&amp;iuml;', '&amp;eth;', '&amp;ntilde;', '&amp;ograve;', '&amp;oacute;', '&amp;ocirc;', '&amp;otilde;', '&amp;ouml;', '&amp;times;', '&amp;oslash;', '&amp;ugrave;', '&amp;uacute;', '&amp;ucirc;', '&amp;uuml;', '&amp;yacute;', '&amp;thorn;', '&amp;szlig;', '&amp;agrave;', '&amp;aacute;', '&amp;acirc;', '&amp;atilde;', '&amp;auml;', '&amp;aring;', '&amp;aelig;', '&amp;ccedil;', '&amp;egrave;', '&amp;eacute;', '&amp;ecirc;', '&amp;euml;', '&amp;igrave;', '&amp;iacute;', '&amp;icirc;', '&amp;iuml;', '&amp;eth;', '&amp;ntilde;', '&amp;ograve;', '&amp;oacute;', '&amp;ocirc;', '&amp;otilde;', '&amp;ouml;', '&amp;divide;', '&amp;oslash;', '&amp;ugrave;', '&amp;uacute;', '&amp;ucirc;', '&amp;uuml;', '&amp;yacute;', '&amp;thorn;', '&amp;yuml;', '&amp;quot;', '&amp;amp;', '&amp;lt;', '&amp;gt;', '&amp;oelig;', '&amp;oelig;', '&amp;scaron;', '&amp;scaron;', '&amp;yuml;', '&amp;circ;', '&amp;tilde;', '&amp;ensp;', '&amp;emsp;', '&amp;thinsp;', '&amp;zwnj;', '&amp;zwj;', '&amp;lrm;', '&amp;rlm;', '&amp;ndash;', '&amp;mdash;', '&amp;lsquo;', '&amp;rsquo;', '&amp;sbquo;', '&amp;ldquo;', '&amp;rdquo;', '&amp;bdquo;', '&amp;dagger;', '&amp;dagger;', '&amp;permil;', '&amp;lsaquo;', '&amp;rsaquo;', '&amp;euro;', '&amp;fnof;', '&amp;alpha;', '&amp;beta;', '&amp;gamma;', '&amp;delta;', '&amp;epsilon;', '&amp;zeta;', '&amp;eta;', '&amp;theta;', '&amp;iota;', '&amp;kappa;', '&amp;lambda;', '&amp;mu;', '&amp;nu;', '&amp;xi;', '&amp;omicron;', '&amp;pi;', '&amp;rho;', '&amp;sigma;', '&amp;tau;', '&amp;upsilon;', '&amp;phi;', '&amp;chi;', '&amp;psi;', '&amp;omega;', '&amp;alpha;', '&amp;beta;', '&amp;gamma;', '&amp;delta;', '&amp;epsilon;', '&amp;zeta;', '&amp;eta;', '&amp;theta;', '&amp;iota;', '&amp;kappa;', '&amp;lambda;', '&amp;mu;', '&amp;nu;', '&amp;xi;', '&amp;omicron;', '&amp;pi;', '&amp;rho;', '&amp;sigmaf;', '&amp;sigma;', '&amp;tau;', '&amp;upsilon;', '&amp;phi;', '&amp;chi;', '&amp;psi;', '&amp;omega;', '&amp;thetasym;', '&amp;upsih;', '&amp;piv;', '&amp;bull;', '&amp;hellip;', '&amp;prime;', '&amp;prime;', '&amp;oline;', '&amp;frasl;', '&amp;weierp;', '&amp;image;', '&amp;real;', '&amp;trade;', '&amp;alefsym;', '&amp;larr;', '&amp;uarr;', '&amp;rarr;', '&amp;darr;', '&amp;harr;', '&amp;crarr;', '&amp;larr;', '&amp;uarr;', '&amp;rarr;', '&amp;darr;', '&amp;harr;', '&amp;forall;', '&amp;part;', '&amp;exist;', '&amp;empty;', '&amp;nabla;', '&amp;isin;', '&amp;notin;', '&amp;ni;', '&amp;prod;', '&amp;sum;', '&amp;minus;', '&amp;lowast;', '&amp;radic;', '&amp;prop;', '&amp;infin;', '&amp;ang;', '&amp;and;', '&amp;or;', '&amp;cap;', '&amp;cup;', '&amp;int;', '&amp;there4;', '&amp;sim;', '&amp;cong;', '&amp;asymp;', '&amp;ne;', '&amp;equiv;', '&amp;le;', '&amp;ge;', '&amp;sub;', '&amp;sup;', '&amp;nsub;', '&amp;sube;', '&amp;supe;', '&amp;oplus;', '&amp;otimes;', '&amp;perp;', '&amp;sdot;', '&amp;lceil;', '&amp;rceil;', '&amp;lfloor;', '&amp;rfloor;', '&amp;lang;', '&amp;rang;', '&amp;loz;', '&amp;spades;', '&amp;clubs;', '&amp;hearts;', '&amp;diams;'
		);

		$aReplace = array(
			'&#160;', '&#161;', '&#162;', '&#163;', '&#164;', '&#165;', '&#166;', '&#167;', '&#168;', '&#169;', '&#170;', '&#171;', '&#172;', '&#173;', '&#174;', '&#175;', '&#176;', '&#177;', '&#178;', '&#179;', '&#180;', '&#181;', '&#182;', '&#183;', '&#184;', '&#185;', '&#186;', '&#187;', '&#188;', '&#189;', '&#190;', '&#191;', '&#192;', '&#193;', '&#194;', '&#195;', '&#196;', '&#197;', '&#198;', '&#199;', '&#200;', '&#201;', '&#202;', '&#203;', '&#204;', '&#205;', '&#206;', '&#207;', '&#208;', '&#209;', '&#210;', '&#211;', '&#212;', '&#213;', '&#214;', '&#215;', '&#216;', '&#217;', '&#218;', '&#219;', '&#220;', '&#221;', '&#222;', '&#223;', '&#224;', '&#225;', '&#226;', '&#227;', '&#228;', '&#229;', '&#230;', '&#231;', '&#232;', '&#233;', '&#234;', '&#235;', '&#236;', '&#237;', '&#238;', '&#239;', '&#240;', '&#241;', '&#242;', '&#243;', '&#244;', '&#245;', '&#246;', '&#247;', '&#248;', '&#249;', '&#250;', '&#251;', '&#252;', '&#253;', '&#254;', '&#255;', '&#34;', '&#38;', '&#60;', '&#62;', '&#338;', '&#339;', '&#352;', '&#353;', '&#376;', '&#710;', '&#732;', '&#8194;', '&#8195;', '&#8201;', '&#8204;', '&#8205;', '&#8206;', '&#8207;', '&#8211;', '&#8212;', '&#8216;', '&#8217;', '&#8218;', '&#8220;', '&#8221;', '&#8222;', '&#8224;', '&#8225;', '&#8240;', '&#8249;', '&#8250;', '&#8364;', '&#402;', '&#913;', '&#914;', '&#915;', '&#916;', '&#917;', '&#918;', '&#919;', '&#920;', '&#921;', '&#922;', '&#923;', '&#924;', '&#925;', '&#926;', '&#927;', '&#928;', '&#929;', '&#931;', '&#932;', '&#933;', '&#934;', '&#935;', '&#936;', '&#937;', '&#945;', '&#946;', '&#947;', '&#948;', '&#949;', '&#950;', '&#951;', '&#952;', '&#953;', '&#954;', '&#955;', '&#956;', '&#957;', '&#958;', '&#959;', '&#960;', '&#961;', '&#962;', '&#963;', '&#964;', '&#965;', '&#966;', '&#967;', '&#968;', '&#969;', '&#977;', '&#978;', '&#982;', '&#8226;', '&#8230;', '&#8242;', '&#8243;', '&#8254;', '&#8260;', '&#8472;', '&#8465;', '&#8476;', '&#8482;', '&#8501;', '&#8592;', '&#8593;', '&#8594;', '&#8595;', '&#8596;', '&#8629;', '&#8656;', '&#8657;', '&#8658;', '&#8659;', '&#8660;', '&#8704;', '&#8706;', '&#8707;', '&#8709;', '&#8711;', '&#8712;', '&#8713;', '&#8715;', '&#8719;', '&#8721;', '&#8722;', '&#8727;', '&#8730;', '&#8733;', '&#8734;', '&#8736;', '&#8743;', '&#8744;', '&#8745;', '&#8746;', '&#8747;', '&#8756;', '&#8764;', '&#8773;', '&#8776;', '&#8800;', '&#8801;', '&#8804;', '&#8805;', '&#8834;', '&#8835;', '&#8836;', '&#8838;', '&#8839;', '&#8853;', '&#8855;', '&#8869;', '&#8901;', '&#8968;', '&#8969;', '&#8970;', '&#8971;', '&#9001;', '&#9002;', '&#9674;', '&#9824;', '&#9827;', '&#9829;', '&#9830;'
		);

		return str_replace($aEntities, $aReplace, $str);
	}

	/**
	 * Convert IP into hexadecimal value
	 * @param string $ip IP
	 * @return mixed
	 */
	static public function ip2hex($ip)
	{
		if (Core_Valid::ip($ip))
		{
			$ip_code = explode('.', $ip);

			if (isset($ip_code[3]))
			{
				return sprintf('%02x%02x%02x%02x', $ip_code[0], $ip_code[1], $ip_code[2], $ip_code[3]);
			}
		}

		return NULL;
	}

	/**
	 * Convert hexadecimal value into IP
	 * @param string $hex source value
	 * @return string
	 */
	static public function hex2ip($hex)
	{
		$aHex = explode('.', chunk_split($hex, 2, '.'));

		$aReturn = array ();

		if (count($aHex) > 0)
		{
			foreach ($aHex as $field)
			{
				if (!empty($field))
				{
					$aReturn[] = hexdec($field);
				}
			}
		}

		return implode('.', $aReturn);
	}

	/**
	 * Регулярное выражение для стоп-слов. Пробелы до и после слова должны обязательно быть указаны
	 *
	 * @var string
	 */
	static protected $_stopWords = '/ (и|в|во|не|что|он|на|я|с|со|как|а|то|все|всё|она|так|его|но|да|ты|к|у|же|вы|за|бы|по|только|её|ее|мне|было|вот|от|меня|ещё|еще|нет|о|из|то|ему|теперь|когда|даже|ну|вдруг|ли|если|уже|или|ни|быть|был|него|до|вас|нибудь|опять|уж|вам|сказал|ведь|там|потом|себя|ничего|ей|может|они|тут|где|есть|надо|ней|для|мы|тебя|их|чем|была|сам|чтоб|без|будто|человек|чего|раз|тоже|себе|под|жизнь|будет|ж|тогда|кто|этот|говорил|того|потому|этого|какой|совсем|ним|здесь|этом|один|почти|мой|тем|чтобы|нее|кажется|сейчас|были|куда|зачем|сказать|всех|никогда|сегодня|можно|при|наконец|два|об|другой|хоть|после|над|больше|тот|через|эти|нас|про|всего|них|какая|много|разве|сказала|три|эту|моя|впрочем|хорошо|свою|этой|перед|иногда|лучше|чуть|том|нельзя|такой|им|более|всегда|конечно|всю|между) /u';

	/**
	 * Метод очищает HTML от ненужных тегов, хеширует и возвращает массив хэшей слов
	 *
	 * @param string $text исходный текст;
	 * @param array $param массив дополнительных параметров
	 * - $param['hash_function'] = 'md5' {'md5','crc32',''} используемая ХЭШ-функция;
	 *
	 * @return array массив хэшей слов
	 */
	static public function getHashes($text, $param = array())
	{
		$text = strip_tags($text);
		$text = mb_strtolower($text);

		if (!isset ($param['hash_function']))
		{
			$param['hash_function'] = 'md5';
		}

		$replace = array(
			"/([a-zA-Zа-яА-ЯёЁ])([0-9])/iu" => '\\1 \\2',
			"/([0-9])([a-zA-Zа-яА-ЯёЁ])/iu" => '\\1 \\2'
		);

		$text = preg_replace(array_keys($replace), array_values($replace), $text);
		$text = str_replace(array("\n", "\r"), array(' ', ''), $text);

		// Дополняем пробелами для правильного удаления стоп-слов '<пробел><стоп-слово><пробел>'
		$text = ' ' . $text . ' ';

		// Удаляем из текста стоп слова
		$text = preg_replace(self::$_stopWords, ' ', $text);

		$text = str_replace('\\', '', $text);

		// Удаляем скрипты, теги и спецсимволы
		$search = array (/*"'<script[^>]*?>.*?</script>'siu",
		"'<style[^>]*?>.*?</style>'siu",
		"'<select[^>]*?>.*?</select>'siu",
		"'<head[^>]*?>.*?</head>'siu",*/
		"'<[^>]*?>'",
		"'([\r\n])[\s]+'",
		"'&(quot|#34);'i",
		"'&(amp|#38);'i",
		"'&(lt|#60);'i",
		"'&(gt|#62);'i",
		"'&(nbsp|#160);'i", // without 'u
		"'&(cent|#162);'i",
		"'&(pound|#163);'i",
		"'&(copy|#169);'i",
		"'&(laquo|#171);'i",
		"'&(raquo|#187);'i",
		"'-|--|[.,!?:;^&@)(><\"\'#}{\$/|_]'i",
		"/&#(\d+);/e",
		"'[ ]+ '");

		$replace = array (/*" ",
		" ",
		" ",
		" ",*/
		" ",
		"\\1",
		"\"",
		"&",
		"<",
		">",
		" ",
		"¢",
		"£",
		"©",
		"«",
		"»",
		" ",
		"chr(\\1)",
		" ");

		$text = preg_replace($search, $replace, $text);

		// 0xC2A0 (C2 A0) - NO-BREAK SPACE, http://www.utf8-chartable.de/
		$search = array(
			"\"", "&", "<", ">", ".", ",", ";", "*",
			":", "'", "-", "=", "{", "}", "(", ")",
			"«", "»", chr(0xC2).chr(0xA0)
		);
		$text = str_replace($search, ' ', $text);

		// Убираем двойные пробелы
		while (stristr($text, '  '))
		{
			$text = str_replace('  ', ' ', $text);
		}

		$text = trim($text);
		$result = explode(' ', $text);

		// Нормализация и хеширование слов
		foreach ($result as $key => $res)
		{
			$word = $res;

			switch ($param['hash_function'])
			{
				case '' :
					$result[$key] = $word;
					break;
				default:
				case 'md5' :
					$result[$key] = md5($word);
					break;
				case 'crc32' :
					$result[$key] = Core::crc32($word);
					break;
			}
		}

		return $result;
	}

	/**
	 * Получение существительного в форме, соответствующей числу
	 *
	 * @param int $int число, с которым связано существительное
	 * @param string $word основа слова
	 * @param array $aEndings массив окончаний слова
	 * <code>
	 * <?php
	 *
	 * $word = 'новост';
	 * $aEndings = array('ей', 'ь', 'и', 'и', 'и', 'ей', 'ей', 'ей', 'ей', 'ей');
	 *
	 * for ($int = 0; $int < 100; $int++)
	 * {
	 * 	$result = Core_Str::declension($int, $word, $aEndings);
	 * 	echo "{$num} {$result} <br />";
	 * }
	 * ?>
	 * </code>
	 * @return string
	 */
	static public function declension($int, $word, $aEndings)
	{
		$lastInt = $int % 100;

		$lastInt = $lastInt > 10 && $lastInt < 20
			? 9
			: $int % 10;

		return $word . $aEndings[$lastInt];
	}

	/**
	 * Удаление HTML-тегов вместе с атрибутами
	 *
	 * @param string $sSource Исходная строка
	 * @param string $aAllowedTags Список разрешенных тегов, например, "<b><i><strong>"
	 * @param array $aDisabledAttributes Массив запрещенных атрибутов тегов, например array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavaible', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragdrop', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterupdate', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmoveout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload')
	 * @return string
	 */
	static public function stripTags($sSource, $aAllowedTags = '', $aDisabledAttributes = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavaible', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragdrop', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterupdate', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmoveout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'))
	{
		$sSource = strval($sSource);
		$aAllowedTags = strval($aAllowedTags);

		if (empty($aDisabledAttributes))
		{
			$result = strip_tags($sSource, $aAllowedTags);
		}
		else
		{
			$result = preg_replace('/<(.*?)>/ieu', "'<' . preg_replace(array('/javascript:[^\"\']*/iu', '/(" . implode('|', $aDisabledAttributes) . ")[ \\t\\n]*=[ \\t\\n]*[\"\'][^\"\']*[\"\']/i', '/\s+/'), array('', '', ' '), stripslashes('\\1')) . '>'", strip_tags($sSource, $aAllowedTags));
		}

		return $result;
	}

	/**
	 * Escaping quotes and line breaks
	 * @param string $str source string
	 * @return string
	 */
	static public function escapeJavascriptVariable($str)
	{
		return str_replace(array("\\", "'", "\r", "\n"), array("\\\\", "\'", '\r', '\n'), $str);
	}

	/**
	 * Convert BR to NL
	 * @param string $string source string
	 * @param string $lineBreak line break character
	 * @return string
	 */
	static public function br2nl($string, $lineBreak = PHP_EOL)
	{
		return preg_replace(array("/(<br>|<br \/>|<br\/>)\s*/i", "/(\r\n|\r|\n)/"), array(PHP_EOL, $lineBreak), $string);
	}

	/**
	 * Convert size from 10M to bytes
	 *
	 * @param string $str e.g. 10M
	 * @return int
	 */
	static public function convertSizeToBytes($str)
	{
		$str = trim($str);
		if (strlen($str) > 0)
		{
			$cLastAlpha = strtolower(substr($str, -1));
			$size = intval($str);
			switch($cLastAlpha)
			{
				case 't':
					$size *= 1024;
				case 'g':
					$size *= 1024;
				case 'm':
					$size *= 1024;
				case 'k':
					$size *= 1024;
			}
		}
		else
		{
			$size = 0;
		}
		return $size;
	}

	/**
	 * ucfirst for utf-8 string
	 * @param string $str source string
	 * @return string
	 */
	static public function ucfirst($str)
	{
		if (mb_strlen($str))
		{
			$str = mb_strtoupper(mb_substr($str, 0, 1)) . mb_substr($str, 1);
		}
		return $str;
	}
}