только целое слово без регулярного выражения

Поскольку я не могу использовать preg_match (поддержка UTF8 каким-то образом нарушена, она работает локально, но ломается при производстве), я хочу найти другой способ сопоставить слово с черным списком. Проблема в том, что я хочу искать строку только для точного совпадения, а не для первого вхождения строки.

Вот как я это делаю с preg_match

preg_match('/\b(badword)\b/', strtolower($string));

Пример строки:

$string = "This is a string containing badwords and one badword";

Я хочу сопоставить только «плохие слова» (в конце), а не «плохие слова».

strpos('badword', $string) matches the first one

Любые идеи?


person Timur    schedule 12.09.2013    source источник
comment
Разбейте строку на пробелы и проверьте каждое слово по вашему черному списку   -  person jonhopkins    schedule 12.09.2013
comment
@jonhopkins Это не сработает для пунктуации (при условии, что она будет).   -  person Grim...    schedule 12.09.2013
comment
Верно.. Не подумал об этом. Хотя есть ли способ убрать знаки препинания?   -  person jonhopkins    schedule 12.09.2013
comment
Как именно он ломается при изготовлении? Какая у вас версия PHP и какая версия PHP рабочего сервера?   -  person Henrique Barcelos    schedule 12.09.2013
comment
@HenriqueBarcelos просто не совпадает, в итоге я использовал mb_ereg вместо preg_match - добился цели.   -  person Timur    schedule 18.09.2013


Ответы (4)


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

  • Используйте strpos с чем-то вроде strpos(' badword ', $string) в цикле while, чтобы продолжать итерацию по всему документу;
  • Разделите строку на пробелы и сравните каждое слово со списком плохих слов, которые у вас есть.

Итак, если вы попытаетесь использовать первый вариант, это будет примерно так (непроверенный псевдокод)

$documet = body of text to process . ' ' 
$document.replace('!@#$%^&*(),./...', ' ')
$document.toLowerCase()
$arr_badWords = [...]
foreach($word in badwords)
{
    $badwordIndex = strpos(' ' . $word . ' ', $document)
    while(!badWordIndex)
    {
        //
        $badwordIndex = strpos($word, $document)
    }
}

РЕДАКТИРОВАТЬ: Согласно предложению @jonhopkins, добавление пробела в конце должно соответствовать сценарию, в котором нужное слово находится в конце документа и не сопровождается знаком препинания.

person npinti    schedule 12.09.2013
comment
А если плохое слово самое первое слово в документе или последнее слово и после него не было знаков препинания? Я не думаю, что это будет соответствовать этому. Но можно ли добавить пробел в начало и конец $document просто для уверенности? - person jonhopkins; 12.09.2013
comment
@jonhopkins: я согласен. Изменил ответ в соответствии с вашим предложением. - person npinti; 12.09.2013

Если вы хотите имитировать модификатор \b регулярного выражения, вы можете попробовать что-то вроде этого:

$offset = 0;
$word = 'badword';
$matched = array();
while(($pos = strpos($string, $word, $offset)) !== false) {
    $leftBoundary = false;
    // If is the first char, it has a boundary on the right
    if ($pos === 0) {
       $leftBoundary = true;
    // Else, if it is on the middle of the string, we must check the previous char
    } elseif ($pos > 0 && in_array($string[$pos-1], array(' ', '-',...)) {
        $leftBoundary = true;
    }

    $rightBoundary = false;
    // If is the last char, it has a boundary on the right
    if ($pos === (strlen($string) - 1)) {
       $rightBoundary = true;
    // Else, if it is on the middle of the string, we must check the next char
    } elseif ($pos < (strlen($string) - 1) && in_array($string[$pos+1], array(' ', '-',...)) {
        $rightBoundary = true;
    }

    // If it has both boundaries, we add the index to the matched ones...
    if ($leftBoundary && $rightBoundary) {
        $matched[] = $pos;
    }

    $offset = $pos + strlen($word);
}
person Henrique Barcelos    schedule 12.09.2013

Вы можете использовать strrpos() вместо strpos:

strrpos — Находит позицию последнего вхождения подстроки в строку

$string = "This is a string containing badwords and one badword";
var_dump(strrpos($string, 'badword'));

Выход:

45
person Amal Murali    schedule 12.09.2013
comment
Это предполагает, что строка известна программисту. Если строка извлекается из пользовательского ввода, возможно, слово из черного списка может стоять перед другим словом, которое будет соответствовать, поэтому это не обязательно работает ни для чего, кроме приведенного выше тестового примера. - person jonhopkins; 12.09.2013

Простой способ использовать границы слов со свойствами юникода:

preg_match('/(?:^|[^pL\pN_])(badword)(?:[^pL\pN_]|$)/u', $string);

На самом деле все намного сложнее, посмотрите здесь.

person Toto    schedule 12.09.2013