Exileum
@Exileum
PHP-программист

Обработка текста в PHP регулярным выражением

Доброго времени суток.

Собственно столкнулся с одной проблемой, самостоятельно решить которую не могу. Необходимо обрабатывать средствами PHP вводимый пользователями текст для передачи его поисковому движку Sphinx. Поиск производится по всем имеющимся словам, а не фразе. Для этого перед каждым отдельным словом добавляем оператор +.

Для данной цели использую следующую функцию:

function clean_text_match ($text, $all_words)
{
	global $db, $bb_cfg;

	$text = ' '. mb_strtolower($text, 'UTF-8') .' ';

	if ($all_words)
	{
		$text = preg_replace('#\s(\b\w)#', ' +$1', $text);
	}
	$text_match_sql = $db->escape(trim($text));

	return $text_match_sql;
}

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

секс в большом городе


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

+sex +and +the +city


Как видите — русский текст через регулярное выражение по непонятной мне причине не проходит. С английским — все отлично. Все текстовые фразы на обработку поступают в уже нужной кодировке (UTF-8) и в принципе каких-либо проблем с самим текстом быть не должно. Следовательно, проблема в самом регулярном выражении.

Немного упрощаем его до вот такой конструкции:

...
	if ($all_words)
	{
		$text = preg_replace('#\s#', ' +$1', $text);
	}
...


Прогоняем русский текст:

+секс +в +большом +городе +


Вроде как все отлично (кроме последнего пробела также получившего +). Однако, если я захочу использовать другие операторы Sphinx, например оператор NOT (! или -), то в результате прогонки текста с таким отрицанием (отрицаем слово город) иметь будем следующее:

+секс +в +большом +-городе +


Что является неверным, т.к. в идеале мы в случае отрицания должны иметь следующий текст:

+секс +в +большом -городе


Поиски похожего регулярного выражения, которое сможет разбивать слова определенными символами, пропуская те, перед которыми уже есть не пробельный символ (@,!,- и т.д.) у меня успехом не увенчались. Поэтому и обращаюсь с просьбой о помощи сюда: есть ли способ осуществить задуманное с иным регулярным выражением?

Во время поисков наткнулся на вот такой комментарий: ru2.php.net/manual/ru/regexp.reference.escape.php#102868 — судя по всему, управляющая последовательность \b просто не дружит с юникодом.

Спасибо.
  • Вопрос задан
  • 4973 просмотра
Решения вопроса 1
ertaquo
@ertaquo
Попробуйте модификатор u:
$text = preg_replace('#\s#u', ' +$1', $text);
www.php.net/manual/ru/reference.pcre.pattern.modifiers.php
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
barmaley_exe
@barmaley_exe
1. Для использования юникода нужен соответствующий модификатор.
2. Символы, попадающие под действие \w зависят от локали. Проверьте локаль, а лучше — замените \w на [a-zа-яё].
Ответ написан
taliban
@taliban
php программист
public function clean_text_match ($text, $all_words)
{
	//global $db, $bb_cfg;
	
	$text = ' '. mb_strtolower($text, 'UTF-8') .' ';
	
	if ($all_words)
	{
		$text = preg_replace('#\s(\b\w)#', ' +$1', $text);
	}
	//$text_match_sql = $db->escape(trim($text));
	
	return $text;
}
	
public function aaaAction()
{
	echo $this->clean_text_match( 'секс в большом городе', true );
}


результат: +секс +в +большом +городе
Вы уверены что получаете правильную строку?
Ответ написан
Begetan
@Begetan
Цитирую, не мое но нашел и мне тоже интересно.

В PCRE есть специальные последовательности для различных классов Unicode-символов, например, «\p{L}» — это буквы, «\p{N}» — цифры и так далее.


Для начала напишите: $text = preg_replace('#\s(\b\pLN)#', ' +$1', $text);

Ну а далее есть еще другие методы:

bolknote.ru/2010/09/08/~2704#29
Ответ написан
Комментировать
Begetan
@Begetan
Точнее просто \pL

И поиграться
www.php.net/manual/ru/regexp.reference.unicode.php

Где «Совпадение символов по Unicode свойству не является быстрой операцией, потому для этой цели PCRE необходимо осуществить поиск в структуре данных с более чем пятнадцатью тысяч символов. Поэтому традиционные управляющие последовательности в PCRE, такие как \d и \w, не используют Unicode свойства. „
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы