Соответствовать литеральной строке - PullRequest
0 голосов
/ 22 декабря 2009

У меня есть эта веб-страница, где пользователи могут добавлять смайлики в свои комментарии. И я хочу ограничить количество смайликов на комментарий. «Система» работает, но у меня есть некоторые проблемы с частью регулярных выражений. Мои смайлики определены в файле конфигурации примерно так:

$config['Smilies'] = Array (
    // irrelevant stuff
    'smilies' => Array (
        ':)' => 'smile.gif',
        ':(' => 'sad.gif',
        // some more smilies
        's:10' => 'worship.gif',
        's:11' => 'zip.gif',
        's:12' => 'heart.gif',
        // some more smilies
        's:1' => 'dry.gif',
        's:2' => 'lol.gif',
        's:3' => 'lollol.gif',
        // some more smilies
    )
);

И затем, когда я проверяю комментарий (чтобы увидеть, сколько там смайликов), я делаю цикл по этому массиву и сопоставляю улыбку с содержанием комментария. Регулярное выражение используется так:

foreach ( $this->config['smilies'] as $smilie => $smilieImage )
{
    $matches = Array ();
    Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '/i', $Content, $matches );

    $numOfFoundSmilies += Count ( $matches[0] );
}

Проблема в том, что если я введу «s: 10» в комментарии, приведенный выше код найдет два совпадения: «s: 10» и «s: 1». Мои знания регулярных выражений очень плохие, и я не могу понять это.

Ответы [ 5 ]

4 голосов
/ 22 декабря 2009

Ваш код подсчитывает для каждого кода улыбки, сколько раз этот код появляется в записи, поэтому s: 10 считается как s: 10, так и s: 1.

Решением будет поиск всех кодов улыбки одновременно, так что каждый фрагмент поста будет учитываться только в одном коде улыбки. Это может быть сделано путем объединения всех кодов в одно регулярное выражение.

$codes = array_keys($smilie);
$escCodes = array_map('preg_quote', $codes);
$regex = '/'.implode('|',$escCodes).'/i';

preg_match_all($regex, $Content, $matches);

$found = count($matches);
3 голосов
/ 22 декабря 2009

Регулярные выражения жадные по умолчанию (по крайней мере, PCRE). Обычно вы можете обойти это:

/a+/ # selects the whiole string from "aaaaaaa"

/a+?/ # selects only "a"

В вашем случае это мало поможет, так как вы не можете просто вставить знак вопроса где-нибудь. Единственная возможность - изменить порядок вашего поискового массива и мгновенно заменить найденных мест. Найдите first для s:10 и second для s:1 и используйте preg_replace () вместо сопоставления. Таким образом, второй больше не находит первый.

Другая возможность: Разделить ваш поисковый массив на две части. Если вы знаете, что он всегда имеет структуру «:» плюс цифры, вы можете получить регулярное выражение в этом втором цикле, например

Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '(?![0-9])/i', $Content, $matches );

с (?![0-9]) a выражением «смотреть вперед» ищет любой не -знач.

И третий: Если вы разрешаете (== конвертировать) смайлики только в определенных местах, вы можете использовать это:

Preg_Match_All ( '/\b' . Preg_Quote ( $smilie ) . '\b/i', $Content, $matches );

\b - это «граница слова», обычно любая не- (буква, цифра, подчеркивание). Недостатком является то, что не все смайлики (например, "abc ;-) xyz") будут найдены.

1 голос
/ 22 декабря 2009

Я думаю, что этот код быстрее, чем Regex

$replaced = str_replace(array_keys($config['Smilies']), 
                        array_values($config['Smilies']),
                        $message, $count);

Это не решит проблемы с s:1 и s:10, поэтому я бы предложил использовать для этого более четкие обозначения разделителя / границы, например :s10: вместо s:10. Тогда это больше не будет проблемой.

Кроме того, я бы предложил не использовать числовые идентификаторы для этого в любом случае. Скорее всего, пользователям будет неудобно их запоминать. Почему бы не использовать легко запомнить ярлыки, например, :heart: или :lol:?

0 голосов
/ 22 декабря 2009

Измените «s: 1» на «s: 1 [^ 0-9]» - соответствует любому «s: 1», за которым не следует другое число.

0 голосов
/ 22 декабря 2009

Вы можете изменить свое регулярное выражение, чтобы использовать границы слов или \ s (пробел) для соответствия, поэтому s:1 становится \bs:1\b или \ss:1\s. Помните, что при втором методе s:1. не будет совпадать, и обе версии не будут совпадать This is my funny texts:1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...