Ох уж эти кавычки!
02.02.2011 технологии
С «ёлочками» не всё так просто, как иногда кажется. Код для автозамены кавычек я меняю уже третий или четвёртый раз :) Вот вчера человеку подсказал как надо, а ведь неправильно подсказал! Приношу свои извинения и публикую вроде бы уж совсем правильный вариант, хоть и не очень красивый.
Как было в последний раз?
$text = preg_replace("/\"([^\"]+)\"/u", "«$1»", $text);
Проблема такого решения в том, что оно заменит на «ёлочки» даже кавычки для значений атрибутов в HTML-коде. Если HTML в $text не планируется, то нормально, хотя тут глупые лишние слэши.
Правильный вариант
$text = preg_replace('/([^=])"([^"]+[^=])"/u', "$1«$2»", '-'.$text);
$text = mb_substr($text, 1);
К входящей переменной $text добавляется незначащий символ «-», чтобы выражение сработало даже для кавычек, стоящих в самом начале строки. А после этот символ убирается через mb_substr. Здесь ещё не показано указание кодировки для mb_substr, если ваши скрипты не в UTF-8, тогда наверно выражение может сработать неправильно. В Daos для гарантии в index.php прописана такая строчка: mb_internal_encoding('UTF-8');
Комментарии
Комментирование этой статьи закрыто.
« Замучался с IE (javascript) Следи за собой, будь осторожен... »
Не стоит допускать возможность ввода HTML. Иначе получается огоромная XSS дыра. Например можно редиректить всех юзеров куда душе угодно или украсть куки с форума.
Ну а что делать если кавычки вложенные будут… Тут регулярки плохо подходят, надо на автоматах писать.
Можно использовать смотрящие назад утверждения:
$text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text);
(c * и ? мож. надо тестировать)
@Jeck: Нет ничего что бы я не мог сделать с регулярками:
while($text0 != $text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text0 = $text));
да, вот так, конечно:
'/(?<!=)"([^"]*?[^=]|)"/u'
Джек, вложенных кавычек лучше просто избегать. А если и нужны они вдруг внезапно — то изначально их обычно вводят разными. Снаружи ёлки, например, а внутри лапки. Мне лично это не нравится, я и не заморачиваюсь на обработку настолько исключительных случаев.
mrkto, да ты что… Я кажется сказал что это плохое решение а не невозможное. Ну и если уж на то пошло твой код не работает а стиль записи выдает убежденного былокодера.
$text = '"Текст "в" кавычках"';
while($text0 != $text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text0 = $text));
echo $text;
Выведет:
«Текст »в« кавычках»
Тормоз, да тут как раз проблема что заменив кавычки на елочки можно сделать только хуже (см пример выше).
Джек, ну это исключительные ведь случаи. Кстати, ты подсказал мне ещё одно улучшение, спасибо. Перед закрывающей кавычкой надо не [^=], а [^=\s]. Тогда твой "Текст "в" кавычках" обработается вполне приемлемо: "Текст «в» кавычках".
Хм, или даже [\w], так лучше.
Хм, нет, с \w не работает почему-то.
Jeck, да, $text0 должен быть справа чтобы не было нотиса. Насчёт быдлокода не знаю, везде я так конечно не пишу, но здесь это вполне атомарная операция, по моему логично…
А как автоматы узнают где открывающаяся, а где закрывающаяся кавычка (как хотел пользователь?). Можно только предположить, что до закрывающей кавычки не должно быть пробела:
while(($text = preg_replace('/(?<!=)"([^"]*?[^=]|)(?<! )"/u', '«$1»', $text0 = $text)) != $text0);