<?
/*
Константы для удобства. Коды соответствуют символам в win-кодировке, но это
"совпадение":) - на самом деле, скрипт кросскодировочный (win и koi).
*/
define("TAG1","\xAC");
define("TAG2","\xAD");
define("LAQUO","\xAB");
define("RAQUO","\xBB");
define("LDQUO","\x84");
define("RDQUO","\x93");
define("MDASH","\x97");
define("NDASH","\x96");
define("APOS","\xB4");
define("HELLIP","\x85");
// функция-заменялка для тегов
$Refs = array(); // буфер для хранения тегов
$RefsCntr = 0; // счётчик буфера
function yyyTypo($x)
{
global $Refs, $RefsCntr;
$Refs[] = StripSlashes($x[0]);
return TAG1.($RefsCntr++).TAG2;
}
function zzzTypo($x)
{
global $Refs;
return $Refs[$x[1]];
}
function TypoAll($text, $isHTML = true)
{
global $Refs,$RefsCntr;
if($isHTML) {
$Refs = array(); // сбрасываем буфер
$RefsCntr = 0; // счётчик буфера
/*
Вырезаем элементы, содержимое которых мы не должны преобразовывать:
комментарии, скрипты, стили, ещё что-нибудь - по вкусу.
Вырезанные блоки складируем в Refs при помощи функции xxxTypo()
*/
// комментарии
$text = preg_replace_callback('{<!--.*?-->}s', 'yyyTypo', $text);
$PrivateTags = "title|script|style|pre|textarea";
$text = preg_replace_callback('{<\s*('.$PrivateTags.')[\s>].*?<\s*/\s*\1\s*>}is', 'yyyTypo', $text);
// обычные теги
$text = preg_replace_callback('{<(?:[^\'"\>]+|".*?"|\'.*?\')+>}s','yyyTypo',$text);
}
// ОК. Теперь займёмся кавычками
/*
ВЕЛИКОЕ ПРАВИЛО: Кавычки всегда прилегают к словам!
Открывающиеся кавычки
могут встречаться:
в начале строки,
после скобок "([{",
дефиса
пробелов,
ещё одной кавычки
*/
$prequote = '\s\(\[\{";-';
$text = preg_replace('{^"}', LAQUO, $text);
$text = preg_replace('{(?<=['.$prequote.'])"}', LAQUO, $text);
// а это для тех, кто нарушает ВЕЛИКОЕ ПРАВИЛО
$text = preg_replace('{^((?:'.TAG1.'\d+'.TAG2.')+)"}', '\1'.LAQUO, $text);
$text = preg_replace('{(?<=['.$prequote.'])((?:'.TAG1.'\d+'.TAG2.')+)"}', '\1'.LAQUO, $text);
/*
Закрывающиеся кавычки - все остальные
Вы спросите - а как же тогда ставить знак дюйма? Очень просто - "!
*/
$text = str_replace('"', RAQUO, $text);
// исправляем ошибки в расстановке кавычек типа ""... и ...""
// (предполагаем, что не более двух-трёх кавык подряд)
$text = preg_replace('{'.LAQUO.RAQUO.'}', LAQUO.LAQUO, $text);
$text = preg_replace('{'.RAQUO.LAQUO.'}', RAQUO.RAQUO, $text);
// вложенные кавыки
$i=0; // - это защита от зацикливания (оно возможно в случае неправильно расставленных кавычек)
while (($i++<10) && preg_match('{'.LAQUO.'(?:[^'.RAQUO.']*?)'.LAQUO.'}', $text))
$text = preg_replace(
'{'.LAQUO.'([^'.RAQUO.']*?)'.LAQUO.'(.*?)'.RAQUO.'}s',
LAQUO.'\1'.LDQUO.'\2'.RDQUO, $text);
$i=0;
while (($i++<10) && preg_match('{'.RAQUO.'(?:[^'.LAQUO.']*?)'.RAQUO.'}', $text))
$text = preg_replace(
'{'.RAQUO.'([^'.LAQUO.']*?)'.RAQUO.'}',
RDQUO.'\1'.RAQUO, $text);
// с кавычками закончили, займёмся мелкой типографикой
// тире:
$text = preg_replace('{^-+(?=\s)}',MDASH,$text);
$text = preg_replace('{(?<=[\s'.TAG2.'])-+(?=\s)}',MDASH,$text);
$text = str_replace(' '.MDASH,' '.MDASH,$text);
// ndash:
$text = preg_replace('{(?<=\d)-(?=\d)}',NDASH,$text);
// ...:
$text = str_replace('...',HELLIP,$text);
// апостроф:
$text = preg_replace('{(?<=\S)\'}',APOS,$text);
if($isHTML)
{
// возвращаем взятое обратно
while (preg_match('{'.TAG1.'.+?'.TAG2.'}', $text))
$text = preg_replace_callback('{'.TAG1.'(.+?)'.TAG2.'}', 'zzzTypo', $text);
}
// заменяем коды символов на HTML-entities.
$text = str_replace(
array(LAQUO,RAQUO,LDQUO,RDQUO,MDASH,NDASH,HELLIP,APOS),
array('«','»','„','“','—','–','…','’'),
$text
);
return $text;
}
?>