Модераторы: Aliance, skyboy, MoLeX, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [RegEx]извлечение слов из строки, с (вложенными)кавычками 
V
    Опции темы
Splendid
Дата 19.11.2007, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



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

и фразу "Закон Республики Беларусь "О печати"" оно сейчас разбивает на:
1. Закон Республики Беларусь
2. о
3. печати

Ну а надо, чтобы разбивало так: 
1. Закон Республики Беларусь "О печати".

Вот...помогите, пожалуйста...

Код

   $pattern = '/(?(?=\")\"([^\"]+)\"|(\+|-)?(\b\w+\b))/iUs';



 


PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Здесь можно зацепиться за "" - две рядомстоящие кавычки.

Попробуйте так:
$pattern = '/(?(?=\")\".*\"(?![^\"]*\"\")|(\+|-)?(\b\w+\b))/iUs';

PS из-за этого, может быть, глючить будет в каких-нибудь хитрых местах.
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



kasmanaft, спасибо!
Но это ведь частный случай - две рядом стоящие кавычки...
здесь скорее как-то надо типа с первой кавычки по последнюю кавычку...просто я в регулярках не сильна, поэтому и спрашиваю
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



" издали " закон " о печати " блаблабла " " - вот попробуйте определить, что я здесь взял в кавычки smile 

По идее хотел вот так: "издали "закон "о печати" блаблабла""

 . . . . 

 smile О да!.. кой-чего пришло: перез закрывающей кавычкой не должно стоять пробела. А число закрывающих должно соответствовать числу уже открытых. Как бы это записать теперь smile


PM MAIL   Вверх
Splendid
Дата 19.11.2007, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



kasmanaftsmile) вопрос интересныйsmile

у меня с этой регуляркой еще одна проблема возникла, при переносе на сервер она странно разбивает слова, например экран ищет как 2 слова: "к" и "ан", в чем здесь может быть проблема???

в некоторых словах обрезает последнюю букву, а некоторые нормально ищет...
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Я сейчас подумаю как записать то, что напридумывал.. А ты покажи пока код свой. А то в зависимости от того какой функцией разбиваешь, разные проблемы могут быть..

И скорее всего предыдущую рег. экспу придется разбить на две... Потому что получится слишком заумно (а она и так, надо сказать, непростая)
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



вот код:
Код

function prepareWhere($search, $fields)
{
    if ($search!=''){
    // Разбираем строку на слова
    $reg = '/(?(?=")"([^"]+)"|(\+|-)?(\b\w+\b))/iUs';
   preg_match_all($reg, $search, $words, PREG_PATTERN_ORDER);
    
    $words_groups = array();
    $words_groups['include']=array();
    $words_groups['exclude']=array();
    $words_groups['any']=array();
    
    // Каждое слово обрабатываем, определяем его тип
    foreach( $words[0] as $word )
    {
        $word = trim($word); // Удаляем лишние пробелы
        if( strlen($word) > 0 ) // Если слово не пустое, то продалжаем с ним
        {
            $word = mysql_real_escape_string($word);
            $word = addCslashes($word, '_%');
            switch( $word[0] )
            {
                case '+': // Обязательные слова
                    $words_groups['include'][] = substr($word, 1);
                    break;
                case '-': // Ненужные слова
                    $words_groups['exclude'][] = substr($word, 1);
                    break;
                default: // Наличие хотя бы одного слова
                    $word = str_replace(array('\\','"'), '', $word);
                    $words_groups['any'][] = $word;  
            }
        }
    }
    
    // "Группируем" группы слов, учитывая поля 
    $words_rules = array();
    $words_rules['include']=array();
    $words_rules['exclude']=array();
    $words_rules['any']=array();
    
    foreach( $fields as $field )
    {
        // Ненужные слова
        if( count($words_groups['exclude']) > 0 )
        
        $words_rules['exclude'][] = ' ('.$field.' NOT LIKE "%'. implode('%" AND '.$field.' NOT LIKE "%', $words_groups['exclude']) .'%" OR '.$field.' is null) ';
        
        // Наличие хотя бы одного слова            
        if( count($words_groups['any']) > 0 )

            $words_rules['any'][] = ' ('.$field.' LIKE "%'. implode('%" OR '.$field.' LIKE "%', $words_groups['any']) .'%") ';
    }
    
        if( count($words_groups['include']) > 0 ) 
        foreach( $words_groups['include'] as $word )
 
            $words_rules['include'][] = ' ('.implode(' LIKE "%'.$word.'%" OR ', $fields).' LIKE "%'.$word.'%") ';
            
    
    // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
 $where = implode(' AND ', $where);
    return $where;
    }
}
;
$where = prepareWhere($search, $table_columns_exp);


Добавлено через 30 секунд
причем локально все работает правильно
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 16:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Ну начнем...

Придумал вот что: /"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is
Второе выражение, наверное, нужно вот таким оставить: (\+|-)(\b\w+\b) - убрал "+" после первой скобки, по-моему, он там не нужен. (объединить два выражения уже не получится, в первом использована рекурсия).

Итого тебе осталось два раза использовать preg_match_all() и после этого объединить полученные массивы (третий аргумент).

Проблемы на сервере могут быть из-за неправильно настроенной локали. Посмотри setlocale().
Может быть получится вот так setlocale (LC_ALL, array ('ru_RU.CP1251', 'rus_RUS.1251')), а может быть придется имена локалей уточнить у хостера.

Цитата
просто я в регулярках не _сильна_

Упс, а я и не приметил smile 
В таком случае, если чего не получится, помогу довести всё это дело до конца  smile  smile 

Это сообщение отредактировал(а) kasmanaft - 19.11.2007, 16:30
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



Настройки локали у меня такие прописаны...но все равно глюки...

я уже вообще ничего не соображаю....
Помогите Ваши регулярки в мой код подставить, пожалуйста..
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Цитата(Splendid @  19.11.2007,  16:38 Найти цитируемый пост)
Настройки локали у меня такие прописаны...но все равно глюки...
Попробуйте у хостера узнать их точное название.. По-моему, дело имеено в локали.

Что с кодом:
Поменяйте у себя
Код

    // Разбираем строку на слова
    $reg = '/(?(?=")"([^"]+)"|(\+|-)?(\b\w+\b))/iUs';
   preg_match_all($reg, $search, $words, PREG_PATTERN_ORDER);
на
Код

    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $reg = '/(?:\+|-)\b\w+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    
    $words[0] = array_merge($words1[0], $words2[0]);

Потом надо что-то сделать с str_replace() вот здесь:
Код

                default: // Наличие хотя бы одного слова
                    $word = str_replace(array('\\','"'), '', $word);
                    $words_groups['any'][] = $word; 

Она не должна удалять кавычки внутри запроса, а только по краям (это можно решить с помощью trim($val, '"') ) и, наверное, не надо вообще удалять "\". (т.е. str_replace() заменить на trim() - вроде бы должно сработать)

Конечно же, нужно бы потестировать.

Это сообщение отредактировал(а) kasmanaft - 19.11.2007, 17:28
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



Спасибо! Пойду пробовать!
а если такая локаль, то что прописывать надо: LANG = "ru_RU.UTF-8"????
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Просто заменить те, что были наверху на эту. Но, честно говоря, не знаю, изменит ли это что-нибудь или нет - текст-то ведь в CP1215, а тут UTF-8.

Понял для чего нужен был тот вопросительный знак.. Всё-таки он был нужен.
То есть вот так попровте: $reg = '/(?:\+|-)?\b\w+\b/is';

И насчет локали.. Вы говорите, неправильно ищет слово "экран". А если его в кавычки взять? 
Если так сработает, то можно второе рег. выражение попробовать оформить вот так:
$reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



в кавычках работает...


что же с этой локалью ничего сделать нельзя??? Может можно на серваке установить CP1215? Как вообще в этих случаях поступают?


если подставлять ваши 2 выражения - то выдает кучу ошибок...сейчас приведу их

Добавлено через 2 минуты и 12 секунд

Notice: Undefined variable: where in F:\Program Files\wamp\www\reestr_skript18\search.php on line 153

это отсюда

Код

  // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
 $where = implode(' AND ', $where);
    return $where;
    }
}
;
$where = prepareWhere($search, $table_columns_exp);
$where1 = prepareWhere($search, $table_columns_sert);


надо видимо что-то еще в коде исравить
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Цитата(Splendid @  19.11.2007,  18:12 Найти цитируемый пост)
если подставлять ваши 2 выражения - то выдает кучу ошибок...
Хм... странно.
Я забыл, что кавычки там будут экранированные, поэтому надо: trim($word, '\\"'). (кстати, Вы $val заменили на $word? я просто так, в качестве примера этот код привел..)

. . . . . .

Ага.. понял в чем дело (про trim() не забудте). Вы, видимо, не обратили внимание на вот это:
Цитата(kasmanaft @  19.11.2007,  18:05 Найти цитируемый пост)
Понял для чего нужен был тот вопросительный знак.. Всё-таки он был нужен.То есть вот так попровте: $reg = '/(?:\+|-)?\b\w+\b/is';

Заменить лучше вот таким: $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is'; (это второе выражение)
И попробуйте этот злополучный "экран" поискать (без кавычек).

Цитата
что же с этой локалью ничего сделать нельзя??? Может можно на серваке установить CP1215? Как вообще в этих случаях поступают?
Тут, признаться, не силен smile 

Это сообщение отредактировал(а) kasmanaft - 19.11.2007, 19:05
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



в итоге должно получится вот так?

Код

function prepareWhere($search, $fields)
{
    if ($search!=''){
  // Разбираем строку на слова
    $reg =  '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';

    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $reg = '/(?:\+|-)\b\w+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    
    $words[0] = array_merge($words1[0], $words2[0]);
    
    $words_groups = array();
    $words_groups['include']=array();
    $words_groups['exclude']=array();
    $words_groups['any']=array();
    
    // Каждое слово обрабатываем, определяем его тип
    foreach( $words[0] as $word )
    {
      echo  $word = trim($word); // Удаляем лишние пробелы
        if( strlen($word) > 0 ) // Если слово не пустое, то продалжаем с ним
        {
            $word = mysql_real_escape_string($word);
            $word = addCslashes($word, '_%');
            switch( $word[0] )
            {
                case '+': // Обязательные слова
                    $words_groups['include'][] = substr($word, 1);
                    break;
                case '-': // Ненужные слова
                    $words_groups['exclude'][] = substr($word, 1);
                    break;
                default: // Наличие хотя бы одного слова
                    $word = trim($word, '"');
                    $words_groups['any'][] = $word;  
            }
        }
    }
    
    // "Группируем" группы слов, учитывая поля 
    $words_rules = array();
    $words_rules['include']=array();
    $words_rules['exclude']=array();
    $words_rules['any']=array();
    
    foreach( $fields as $field )
    {
        // Ненужные слова
        if( count($words_groups['exclude']) > 0 )
        
        $words_rules['exclude'][] = ' ('.$field.' NOT LIKE "%'. implode('%" AND '.$field.' NOT LIKE "%', $words_groups['exclude']) .'%" OR '.$field.' is null) ';
        
        // Наличие хотя бы одного слова            
        if( count($words_groups['any']) > 0 )

            $words_rules['any'][] = ' ('.$field.' LIKE "%'. implode('%" OR '.$field.' LIKE "%', $words_groups['any']) .'%") ';
    }
    
        if( count($words_groups['include']) > 0 ) 
        foreach( $words_groups['include'] as $word )
 
            $words_rules['include'][] = ' ('.implode(' LIKE "%'.$word.'%" OR ', $fields).' LIKE "%'.$word.'%") ';
            
    
    // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
 $where = implode(' AND ', $where);
    return $where;
    }
}
;


Вроде все ищет, спасибо огромное!!!

Добавлено через 1 минуту
правда кавычки в кавычках все равно не воспринимаетsmile
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 19:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Нет, чуть-чуть не так smile

Вот.
Код
    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    
    $words[0] = array_merge($words1[0], $words2[0]);


И вот
Код
                default: // Наличие хотя бы одного слова
                    $word = trim($word, '\\"');
                    $words_groups['any'][] = $word;  


UPD ну что ты будешь делать, опять "вопрос" куда-то пропал  smile
Скопируйте заново (я обновил)

Это сообщение отредактировал(а) kasmanaft - 19.11.2007, 19:20
PM MAIL   Вверх
Splendid
Дата 19.11.2007, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



обновила, спасибо!!!
Только с кавычками в кавычках та же историяsmile

Добавлено через 11 минут
странно, еще почему-то у некоторых слов первая или последняя буква отрезается...:(
PM MAIL   Вверх
kasmanaft
Дата 19.11.2007, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Ну как же так же, я с ума сейчас сойду smile  smile  smile 

А что Вы ищете? Может быть, неправильно оформлена строка? Кавычки должны окружать слово (словосочетание), без пробелов. ("текст "текст" текст", а не "текст"текст"текст" или "текст " текст " текст ").
Код

function prepareWhere($search, $fields)
{
    if ($search!=''){
    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    
    $words[0] = array_merge($words1[0], $words2[0]);
    
    $words_groups = array();
    $words_groups['include']=array();
    $words_groups['exclude']=array();
    $words_groups['any']=array();
    
    // Каждое слово обрабатываем, определяем его тип
    foreach( $words[0] as $word )
    {
        $word = trim($word); // Удаляем лишние пробелы
        if( strlen($word) > 0 ) // Если слово не пустое, то продалжаем с ним
        {
            $word = addslashes($word);
            $word = addCslashes($word, '_%');
            switch( $word[0] )
            {
                case '+': // Обязательные слова
                    $words_groups['include'][] = substr($word, 1);
                    break;
                case '-': // Ненужные слова
                    $words_groups['exclude'][] = substr($word, 1);
                    break;
                default: // Наличие хотя бы одного слова
                    $word = trim($word, '"\\');
                    $words_groups['any'][] = $word;  
            }
        }
    }
    
    // "Группируем" группы слов, учитывая поля 
    $words_rules = array();
    $words_rules['include']=array();
    $words_rules['exclude']=array();
    $words_rules['any']=array();
    
    foreach( $fields as $field )
    {
        // Ненужные слова
        if( count($words_groups['exclude']) > 0 )
        
        $words_rules['exclude'][] = ' ('.$field.' NOT LIKE "%'. implode('%" AND '.$field.' NOT LIKE "%', $words_groups['exclude']) .'%" OR '.$field.' is null) ';
        
        // Наличие хотя бы одного слова            
        if( count($words_groups['any']) > 0 )

            $words_rules['any'][] = ' ('.$field.' LIKE "%'. implode('%" OR '.$field.' LIKE "%', $words_groups['any']) .'%") ';
    }
    
        if( count($words_groups['include']) > 0 ) 
        foreach( $words_groups['include'] as $word )
 
            $words_rules['include'][] = ' ('.implode(' LIKE "%'.$word.'%" OR ', $fields).' LIKE "%'.$word.'%") ';
            
    
    // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
 $where = implode(' AND ', $where);
    return $where;
    }
}
;


Добавлено через 6 минут и 51 секунду
Ага, похоже до меня наконец-таки дошло.

Попробуйте после первого preg_match_all() вставить
    $search = preg_replace($reg, "", $search);
То есть
Код

    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $search = preg_replace($reg, "", $search);

    $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);

PM MAIL   Вверх
Splendid
Дата 20.11.2007, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



изменила, ввожу вот так: "Закон Республики Беларусь "О научно-технической информации""

не то ищет...
вот как разбивает:

LIKE "%Закон Республики Беларусь %" OR LIKE "%%" OR  LIKE "%О%" OR  LIKE "%научно-технической%" OR LIKE "%информации%")


до последних изменений разбивал так:
LIKE "%Закон Республики Беларусь %" OR LIKE "%%" OR  LIKE "%Закон%" OR LIKE "%Республики%" OR LIKE "%Беларусь%" OR LIKE "%О%" OR LIKE "%научно-технической%" OR LIKE "%информации%") 


PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Странно.. у меня вот как разбивает:
Если "кавычки в кавычках" : LIKE "%Закон Республики Беларусь \"О научно-технической информации%") )
И без кавычек: LIKE "%О научно-технической информации%" OR LIKE "%Закон%" OR LIKE "%Республики%" OR LIKE "%Беларусь%") )

 smile 

Прикреплю на всякий случай код:
Код

<?php
function prepareWhere($search, $fields)
{
    if ($search!=''){
    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);

    $search = preg_replace($reg, "", $search);

    $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    
    $words[0] = array_merge($words1[0], $words2[0]);
    
    $words_groups = array();
    $words_groups['include']=array();
    $words_groups['exclude']=array();
    $words_groups['any']=array();
    
    // Каждое слово обрабатываем, определяем его тип
    foreach( $words[0] as $word )
    {
        $word = trim($word); // Удаляем лишние пробелы
        if( strlen($word) > 0 ) // Если слово не пустое, то продалжаем с ним
        {
            $word = addslashes($word);
            $word = addCslashes($word, '_%');
            switch( $word[0] )
            {
                case '+': // Обязательные слова
                    $words_groups['include'][] = substr($word, 1);
                    break;
                case '-': // Ненужные слова
                    $words_groups['exclude'][] = substr($word, 1);
                    break;
                default: // Наличие хотя бы одного слова
                    $word = trim($word, '"\\');
                    $words_groups['any'][] = $word;  
            }
        }
    }
    
    // "Группируем" группы слов, учитывая поля 
    $words_rules = array();
    $words_rules['include']=array();
    $words_rules['exclude']=array();
    $words_rules['any']=array();
    
    foreach( $fields as $field )
    {
        // Ненужные слова
        if( count($words_groups['exclude']) > 0 )
        
        $words_rules['exclude'][] = ' ('.$field.' NOT LIKE "%'. implode('%" AND '.$field.' NOT LIKE "%', $words_groups['exclude']) .'%" OR '.$field.' is null) ';
        
        // Наличие хотя бы одного слова            
        if( count($words_groups['any']) > 0 )

            $words_rules['any'][] = ' ('.$field.' LIKE "%'. implode('%" OR '.$field.' LIKE "%', $words_groups['any']) .'%") ';
    }
    
        if( count($words_groups['include']) > 0 ) 
        foreach( $words_groups['include'] as $word )
 
            $words_rules['include'][] = ' ('.implode(' LIKE "%'.$word.'%" OR ', $fields).' LIKE "%'.$word.'%") ';
            
    
    // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
 $where = implode(' AND ', $where);
    return $where;
    }
}
;

echo prepareWhere('Закон Республики Беларусь "О научно-технической информации"', array(''));
?>

PM MAIL   Вверх
Splendid
Дата 20.11.2007, 11:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



я поняла, у меня подставляется вот так:

\"Закон Республики Беларусь \"О научно-технической информации\"\", ибо экранирование есть...

А можно без экранирования в запрос подставлять? Это безопасно?
PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 12:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Нет, конечно, не безопасно.

Но ведь $word = trim($word, '"\\') должен отрезать эти экранированные кавычки.. Вы его заменили?

PS выложил код, забыл кой-чего исправить:
$word = addslashes($word); - вместо него у Вас должен быть 
$word = mysql_real_escape_string($word); 
(с mysql_real_escape_string не работало у меня, т.к. нет соединения с БД)

PSPS ну блин smile  У Вас, похоже, включены магические кавычки, а текст приходит из формы?
Вообще полученный текст сразу же нужно очищать от работы этих магических кавычек вот такой конструпцией:
Код

// получили значение
$search = $_POST['search'];
// если включены магические кавычки
if (get_magic_quotes_gpc())
    // "отменяем" экранирование
    $search = stripslashes($search);

А после этого с $search уже можно работать...

Это сообщение отредактировал(а) kasmanaft - 20.11.2007, 12:21
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



у меня приходит значение из формы, и обрабатывается перед подстановкой в нашу функцию так:

Код

function strips(&$el) { 
  if (is_array($el)) 
    foreach($el as $k=>$v) 
      strips($el[$k]); 
  else $el = stripslashes($el); 

if (get_magic_quotes_gpc()) { 
  strips($_GET);
  strips($_POST);
  strips($_COOKIE); 
  strips($_REQUEST);
  if (isset($_SERVER['PHP_AUTH_USER'])) strips($_SERVER['PHP_AUTH_USER']); 
  if (isset($_SERVER['PHP_AUTH_PW']))   strips($_SERVER['PHP_AUTH_PW']);
}
include "config.php";
include "query.php";
//Введенное пользователем значение
$search = $_REQUEST['search'];
$search=str_replace('\\','\\\\',$search);
$search=mysql_real_escape_string($search);
//убираем знаки препинания
$search=eregi_replace ('[?!()#:;|.]', '', $search);
//Замена нескольких пробелов на один: 
$search=ereg_replace(" +"," ",$search);
//Удаление лишних пробелов по-левому и правому боку текста:
$search=trim($search);
//чтобы _ и % соответствовали точно самим себе
$search=addCslashes($search, '_%');


вот....это правильно? этого достаточно?

Добавлено через 6 минут и 34 секунды
кажется я поняла, мне надо перед функцией убрать 

$search=mysql_real_escape_string($search);


так как в функции уже есть

$word = mysql_real_escape_string($word);  и поэтому происходит двойное экранирование, так?smile
PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Точно!  smile 


Однако вот это лишнее...
Код

//убираем знаки препинания
$search=eregi_replace ('[?!()#:;|.]', '', $search);
//Замена нескольких пробелов на один: 
$search=ereg_replace(" +"," ",$search);
//Удаление лишних пробелов по-левому и правому боку текста:
$search=trim($search);
//чтобы _ и % соответствовали точно самим себе
$search=addCslashes($search, '_%');


Это сообщение отредактировал(а) kasmanaft - 20.11.2007, 12:38
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



ОГРОМНЕЙШЕЕ спасибо!!!! smile  smile 
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



а почему лишнее?

PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



1) знаки препинания - потому что на них функция не станет обращать внимания, т.е. они не помешают. А, если удалить, скажем, запятую, находящуюся в кавычках -  ничего не найдется.
2) Замена нескольких пробелов на один - аналогично знакам препинания...
3) Удаление лишних пробелов по-левому и правому боку текста - тоже незачем..
4) чтобы _ и % соответствовали точно самим себе - эта же функция применяется внутри prepareWhere.. Если два раза экранировать, получится, что экранируется "\", а _% останутся нетронутыми.

PS наконец-то мы её победили smile 
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



не, не мы, а Выsmile я так, прослушала лекциюsmile Спасибо!

Добавлено через 6 минут и 25 секунд
вот еще вылезло: 
если в поисковую строку просто ввести какой-нибудь из символов: . \ , " № ; @ # & ну и так далее, то 
Notice: Undefined variable: where in F:\Program Files\wamp\www\reestr_skript18\search.php on line 151

Добавлено через 12 минут и 4 секунды
что с этим делать?
PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Так-так-таак..
Можно попробовать
Код
 if ($search!=''){
заменить на
Код
if (preg_match("/[а-яА-ЯёЁa-zA-Z0-9]/", $search)){

PS а что раньше было, если передать в функцию пустую строку? 
Если все нормально было, то должно сработать..
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 14:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



раньше с пустой строкой была проверка: 

Код

if ($search == '')
 {echo '</br>';
   echo " <center><br> Вы ничего не ввели в окно поиска.
    Пожалуйста, повторите ввод. </br></center>";
 }


Сейчас с пустой нормально, а вот с этими символами:
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in F:\Program Files\wamp\www\reestr_skript18\search.php on line 173

т.е. $where нету, следовательно запрос неправильный....
значит теперь нужно ввести проверку типа 

if ($where == '')
 {echo '</br>';
   echo " <center><br> То чего-то там. </br></center>";
 }

????

Добавлено через 1 минуту и 37 секунд
т.е. теперь пользователь может вводить только русские и англ. буквы и цифры...так?

Добавлено через 2 минуты и 40 секунд
а почему? регулярные выражения не воспринимают  \ , " № ; @ # & и так далее??
PM MAIL   Вверх
kasmanaft
Дата 20.11.2007, 14:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 16.11.2007

Репутация: 1
Всего: 2



Цитата(Splendid @  20.11.2007,  17:06 Найти цитируемый пост)
т.е. теперь пользователь может вводить только русские и англ. буквы и цифры...так?

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

Раньше, вроде бы, так же было.. Разве нет? И "Notice: Undefined variable" по идее должна была выскакивать при аналогичном вводе.

Сейчас он ищет то, что находится в кавычках и то, что перечисленно во втором выражении
$reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
Это выражение можно на словах расписать так: возможно стоит плюс или минус, после которого идут перечисленные в кв. скобках буквы/числа.

Если нужно искать всё, что введет пользователь, можно квадратные скобки заменить на "\S".
Если хотите ограничить длинну слова (чтобы исключить из поиска слишком короткие слова), можно после квадратных скобок (или \S - что выберете) убрать "+" и поставить "{3,}" - будет искать слова только от трех "букв" и больше.

Вместо это проверки
Код

 if ($search == '')
 {echo '</br>';
   echo " <center><br> Вы ничего не ввели в окно поиска.
    Пожалуйста, повторите ввод. </br></center>";
 }
лучше проверить, что вернула функция. 




Итак. Исходя из вышесказанного, налепил вот что:
Код

<?php
function prepareWhere($search, $fields)
{
    // Разбираем строку на слова
    $reg = '/"(?=\S)(?:[^"]*|(?R))*(?<=\S)"/is';
    preg_match_all($reg, $search, $words1, PREG_PATTERN_ORDER);
    $search = preg_replace($reg, "", $search);
    $reg = '/(?:\+|-)?\b[a-zA-Zа-яёА-ЯЁ0-9-_]+\b/is';
    preg_match_all($reg, $search, $words2, PREG_PATTERN_ORDER);
    $words[0] = array_merge($words1[0], $words2[0]);
    
    $words_groups = array();
    $words_groups['include']=array();
    $words_groups['exclude']=array();
    $words_groups['any']=array();
    
    // Каждое слово обрабатываем, определяем его тип
    foreach( $words[0] as $word )
    {
        if( strlen($word) > 0 ) // Если слово не пустое, то продалжаем с ним
        {
            $word = trim($word, '"');
            $word = mysql_real_escape_string($word);
            $word = addCslashes($word, '_%');
            switch( $word[0] )
            {
                case '+': // Обязательные слова
                    $words_groups['include'][] = substr($word, 1);
                    break;
                case '-': // Ненужные слова
                    $words_groups['exclude'][] = substr($word, 1);
                    break;
                default: // Наличие хотя бы одного слова
                    $words_groups['any'][] = $word;  
            }
        }
    }
    
    // "Группируем" группы слов, учитывая поля 
    $words_rules = array();
    $words_rules['include'] = array();
    $words_rules['exclude'] = array();
    $words_rules['any'] = array();
    
    foreach( $fields as $field )
    {
        // Ненужные слова
        if( count($words_groups['exclude']) > 0 )
            $words_rules['exclude'][] = ' ('.$field.' NOT LIKE "%'. implode('%" AND '.$field.' NOT LIKE "%', $words_groups['exclude']) .'%" OR '.$field.' is null) ';
        
        // Наличие хотя бы одного слова            
        if( count($words_groups['any']) > 0 )
            $words_rules['any'][] = ' ('.$field.' LIKE "%'. implode('%" OR '.$field.' LIKE "%', $words_groups['any']) .'%") ';
    }
    
    if( count($words_groups['include']) > 0 ) 
        foreach( $words_groups['include'] as $word )
            $words_rules['include'][] = ' ('.implode(' LIKE "%'.$word.'%" OR ', $fields).' LIKE "%'.$word.'%") ';
            
    
    // Объединяем результаты
    if( count($words_rules['include']) > 0 )
        $where['include'] = '('.implode(' AND ', $words_rules['include']).')';
    if( count($words_rules['exclude']) > 0 )
        $where['exclude'] = '('.implode(' AND ', $words_rules['exclude']).')'; 
    if( count($words_rules['any']) > 0 )
        $where['any'] = '('.implode(' OR ', $words_rules['any']).')';
   
    if (!empty($where['include']) || !empty($where['exclude']) || !empty($where['any']))
        $where = implode(' AND ', $where);
    else $where = "";
    
    return $where;
}

$where = prepareWhere('fgdf', array(''));

if (empty($where))
{
    echo '</br>';
    echo " <center><br> Вы ничего не ввели в окно поиска.
    Пожалуйста, повторите ввод. </br></center>";
} else {
    /* можно выполнять поиск, используя приготовненную where */
    echo $where;
}

?>
(поправте как надо второе выражение)

PS опять забыл про mysql_real_escape_string(). Обновил smile 

Это сообщение отредактировал(а) kasmanaft - 20.11.2007, 14:41
PM MAIL   Вверх
Splendid
Дата 20.11.2007, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 256
Регистрация: 1.8.2007
Где: Беларусь, Минск

Репутация: нет
Всего: нет



вроде как понятно...smile

Спасибо огромное еще раз!
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Тексты | Следующая тема »


 




[ Время генерации скрипта: 0.1821 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.