Ох уж эти кавычки!

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');

Комментарии

  1. # : 

    Не стоит допускать возможность ввода HTML. Иначе получается огоромная XSS дыра. Например можно редиректить всех юзеров куда душе угодно или украсть куки с форума.

  2. # Jeck

    Ну а что делать если кавычки вложенные будут… Тут регулярки плохо подходят, надо на автоматах писать.

  3. # mrkto

    Можно использовать смотрящие назад утверждения:
    $text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text);

    (c * и ? мож. надо тестировать)

    @Jeck: Нет ничего что бы я не мог сделать с регулярками:
    while($text0 != $text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text0 = $text));

  4. # mrkto

    да, вот так, конечно:
    '/(?<!=)"([^"]*?[^=]|)"/u'

  5. # Тормоз

    Джек, вложенных кавычек лучше просто избегать. А если и нужны они вдруг внезапно — то изначально их обычно вводят разными. Снаружи ёлки, например, а внутри лапки. Мне лично это не нравится, я и не заморачиваюсь на обработку настолько исключительных случаев.

  6. # Jeck

    mrkto, да ты что… Я кажется сказал что это плохое решение а не невозможное. Ну и если уж на то пошло твой код не работает а стиль записи выдает убежденного былокодера.
    $text = '"Текст "в" кавычках"';
    while($text0 != $text = preg_replace('/(?<!=)"([^"]*[^=]?)"/u', '«$1»', $text0 = $text));
    echo $text;
    Выведет:
    «Текст »в« кавычках»

    Тормоз, да тут как раз проблема что заменив кавычки на елочки можно сделать только хуже (см пример выше).

  7. # Тормоз

    Джек, ну это исключительные ведь случаи. Кстати, ты подсказал мне ещё одно улучшение, спасибо. Перед закрывающей кавычкой надо не [^=], а [^=\s]. Тогда твой "Текст "в" кавычках" обработается вполне приемлемо: "Текст «в» кавычках".

  8. # Тормоз

    Хм, или даже [\w], так лучше.

  9. # Тормоз

    Хм, нет, с \w не работает почему-то.

  10. # mrkto: 

    Jeck, да, $text0 должен быть справа чтобы не было нотиса. Насчёт быдлокода не знаю, везде я так конечно не пишу, но здесь это вполне атомарная операция, по моему логично…

    А как автоматы узнают где открывающаяся, а где закрывающаяся кавычка (как хотел пользователь?). Можно только предположить, что до закрывающей кавычки не должно быть пробела:
    while(($text = preg_replace('/(?<!=)"([^"]*?[^=]|)(?<! )"/u', '«$1»', $text0 = $text)) != $text0);

Комментирование этой статьи закрыто.

Интересное Покупки ТехникаРазное Отдых Статьи Строительство Услуги Общество Хобби Культура Советы Уют