Различные результаты между preg_replace и preg_match_all

У меня есть форум, который поддерживает хэштеги. Я использую следующую строку, чтобы преобразовать все хэштеги в ссылки. Я использую шаблон (^|\(|\s|>), чтобы избежать именованных якорей в URL-адресах.

$str=preg_replace("/(^|\(|\s|>)(#(\w+))/","$1<a href=\"/smalltalk.php?Tag=$3&amp;".SID."\">$2</a>",$str);

Я использую эту строку для подбора хэштегов, чтобы сохранить их в отдельном поле, когда пользователь отправляет свое сообщение, это подбирает все хэштеги, КРОМЕ тех, которые находятся в начале новой строки.

preg_match_all("/(^|\(|\s|>)(#(\w+))/",$Content,$Matches);

Использование модификаторов m и s не имеет никакого значения. Что я делаю не так во втором случае?

Редактировать: вводимый текст может быть обычным текстом или HTML. Пример ввода задачи:

#startoftextreplacesandmatches #afterwhitespacereplacesandmatches <b>#insidehtmltagreplacesandmatches</b> :)
#startofnewlinereplacesbutdoesnotmatch :(

person Orinoco    schedule 02.09.2012    source источник
comment
В какой текст помещаются хэштеги? Простой текст? HTML? BBC-код? Уценка? Буквы, высеченные на каменных плитах?   -  person hakre    schedule 02.09.2012
comment
Текст может быть обычным текстом или HTML   -  person Orinoco    schedule 02.09.2012
comment
В случае HTML, я предлагаю вам позаботиться о хэштегах в тексте, например: a #<!-- edit later -->ta<!-- here, too -->g this is, который, вероятно, будет хэштегом #tag. Если это так (или некоторые другие распространенные вещи, которые могут произойти), вас может заинтересовать этот вопрос и ответ: Игнорировать теги html в preg_replace   -  person hakre    schedule 02.09.2012


Ответы (1)


У вашей операции замены есть проблема, с которой вы, очевидно, еще не сталкивались - она ​​позволяет использовать неэкранированные специальные символы HTML. Причина, по которой я это знаю, заключается в том, что ваше регулярное выражение позволяет добавлять к хэштегам префикс >, который является специальным символом.

По этой причине я рекомендую вам использовать этот код для замены, который будет дублироваться как код для извлечения тегов, которые будут вставлены в базу данных:

$hashtags = array();

$expr = '/(?:(?:(^|[(>\s])#(\w+))|(?P<notag>.+?))/';

$str = preg_replace_callback($expr, function($matches) use (&$hashtags) {
    if (!empty($matches['notag'])) {
        // This takes care of HTML special characters outside hashtags
        return htmlspecialchars($matches['notag']);
    } else {
        // Handle hashtags
        $hashtags[] = $matches[2];
        return htmlspecialchars($matches[1]).'<a href="/smalltalk.php?Tag='.htmlspecialchars(urlencode($matches[2])).'&amp;'.SID.'">#'.htmlspecialchars($matches[2]).'</a>';
    }
}, $str);

После запуска приведенного выше кода $str будет содержать измененную строку, правильно экранированную для прямого вывода, а $hashtags будет заполнена всеми совпадающими тегами.

Посмотрите, как это работает

person DaveRandom    schedule 02.09.2012
comment
Пытался проверить, но получил ошибку Parse: синтаксическая ошибка, неожиданная T_FUNCTION в /blahblahblah/smallpost.php в строке 180. Входной текст уже может быть HTML из TinyEditor, я уже удалил ненужные теги и экранировал необходимые символы, прежде чем нажму этот код . Preg_replace работает, а preg_match_all — нет. - person Orinoco; 02.09.2012
comment
@user1641839 user1641839 Ну, в этом случае применяется тот же принцип, это просто означает, что его можно упростить: codepad.viper-7 .com/jfmDvG - person DaveRandom; 02.09.2012
comment
@user1641839 user1641839 Ошибка синтаксического анализа связана с тем, что вы используете PHP ‹ 5.3, одну секунду я дам вам рабочую версию для этого - person DaveRandom; 02.09.2012
comment
@user1641839 user1641839 Хорошо, а как насчет этого? codepad.viper-7.com/D1G7hr — мне пришлось обернуть его в объект, потому что PHP 5.2 не имеет механизма наследования переменных из текущей области. Я знаю, что ваш существующий код замены работает, но я считаю, что, объединив его с поиском по тегу, вы можете решить проблему, с которой вы столкнулись, а также сделать свой код более эффективным, потому что вам нужно запустить регулярное выражение только один раз. - person DaveRandom; 02.09.2012
comment
При работе с этим кодом я обнаружил настоящую проблему - сопоставление выполнялось после того, как текст был экранирован до того, как он был вставлен через sql, который нарушал разрывы строк, замена не имела такого экранирования, потому что оно выполнялось для текста, выходящего из стол, да! Вы правы в том, что ваш код более эффективен, поэтому я буду его использовать. Спасибо за помощь. - person Orinoco; 02.09.2012