2010-06-08 4 views
2

У меня есть структура для хранения информации о лицах и multi_index_contaider для хранения таких объектов. Мультииндекс использует для поиска по различным критериям.Поиск частичной строки в boost :: multi_index_container

Я добавил несколько человек в контейнер и хочу найти человека по фамилии. Он отлично работает, если я использую полное имя. Но он возвращает nothig, если я пытаюсь найти человека по части последнего имени (первые буквы последнего имени).

Как вы знаете, частичный поиск строк работает как очарование для std::set<string>. Таким образом, я только развязал строки структурой и потерял эту функциональность.

Вот компилируемый код:

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <set> 

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/identity.hpp> 
#include <boost/multi_index/member.hpp> 
#include <boost/multi_index/composite_key.hpp> 

#define DEFAULT_ADDRESS "Moscow" 
#define DEFAULT_PHONE "11223344" 

typedef unsigned int uint; 

using namespace boost; 
using namespace boost::multi_index; 

struct person 
{ 
    std::string m_first_name; 
    std::string m_last_name; 
    std::string m_third_name; 
    std::string m_address; 
    std::string m_phone; 

    person(); 
    person(std::string f, std::string l, std::string t = "", std::string a = DEFAULT_ADDRESS, std::string p = DEFAULT_PHONE) : 
     m_first_name(f), m_last_name(l), m_third_name(t), m_address(a), 
     m_phone(p) { } 

    virtual ~person() 
     { /*std::cout << "Destructing person..." << std::endl;*/ } 

    person& operator=(const person& rhs); 
}; 

typedef multi_index_container< 
    person, 
    indexed_by< 
     ordered_unique<identity<person> >, 
     ordered_non_unique< 
      composite_key< 
       person, 
       member<person, std::string, &person::m_last_name>, 
       member<person, std::string, &person::m_first_name>, 
       member<person, std::string, &person::m_third_name> 
      > 
     > 
    > 
> persons_set; 

person& person::operator=(const person &rhs) 
{ 
    m_first_name = rhs.m_first_name; 
    m_last_name = rhs.m_last_name; 
    m_third_name = rhs.m_third_name; 
    m_address = rhs.m_address; 
    m_phone = rhs.m_phone; 
    return *this; 
} 

bool operator<(const person &lhs, const person &rhs) 
{ 
    if(lhs.m_last_name == rhs.m_last_name) 
    { 
     if(lhs.m_first_name == rhs.m_first_name) 
      return (lhs.m_third_name < rhs.m_third_name); 

     return (lhs.m_first_name < rhs.m_first_name); 
    } 
     return (lhs.m_last_name < rhs.m_last_name); 
} 

std::ostream& operator<<(std::ostream &s, const person &rhs) 
{ 
    s << "Person's last name: " << rhs.m_last_name << std::endl; 
    s << "Person's name: " << rhs.m_first_name << std::endl; 
    if (!rhs.m_third_name.empty()) 
     s << "Person's third name: " << rhs.m_third_name << std::endl; 
    s << "Phone: " << rhs.m_phone << std::endl; 
    s << "Address: " << rhs.m_address << std::endl << std::endl; 
    return s; 
} 

struct comp_persons 
{ 
    bool operator()(const person& p1, const person& p2) const 
    { 
     if (p2.m_last_name.empty()) return false; 
     return (p1.m_last_name.find(p2.m_last_name) == 0); 
    } 
}; 



int main() 
{  
    persons_set my_set; 

    persons_set::nth_index<0>::type &general_index = my_set.get<0>(); // shortcut to the 1st index 
    persons_set::nth_index<1>::type &names_index = my_set.get<1>(); // shortcut to the 2nd index 

    // adding persons 
    general_index.insert(person("Alex", "Johnson", "Somename")); 
    general_index.insert(person("Alex", "Goodspeed")); 
    general_index.insert(person("Peter", "Goodspeed")); 
    general_index.insert(person("Akira", "Kurosava")); 

    // search via 2nd index (based on last_name) 
    std::pair<persons_set::nth_index<1>::type::const_iterator, persons_set::nth_index<1>::type::const_iterator> 
     n_it = names_index.equal_range("Goodspeed"); 

    // this finds nothing 
    /*std::pair<persons_set::nth_index<1>::type::const_iterator, persons_set::nth_index<1>::type::const_iterator> 
     n_it = names_index.equal_range("Goodspe");*/ 

    // idea by Kirill V. Lyadvinsky. This code crashes on the start. 
    // I guess because behaviour of comp_persons differs from default less<> or reloaded operator < 
    /*std::pair<persons_set::nth_index<1>::type::const_iterator, persons_set::nth_index<1>::type::const_iterator> 
     n_it = std::equal_range(names_index.begin(), names_index.end(), person("Alex", "Goodspe"), comp_persons());*/ 

    std::copy(n_it.first ,n_it.second, 
     std::ostream_iterator<person>(std::cout)); 

    return 0; 

} 
+0

Если вы представили минимальны, _compilable_ кода, который дублирует вашу проблему (и не разбросан по нескольким параграфам текст), вы можете получить больше людей, желающих попытаться решить вашу проблему. –

+0

Спасибо за ваше предложение. Теперь он выглядит красивее, и исходный код компилируется. – Titan

+0

Что вы подразумеваете под «частичным поиском строк» ​​как шарм для 'std :: set ' "? Например, см. Http://codepad.org/IYi8R3cW. –

ответ

1

Вы можете использовать equal_range или lower_bound с пользовательскими сравнения функтора. Он может выглядеть следующим образом (не проверено):

struct comp_substr { 
    bool operator()(const char* input, const std::string& s) const { 
    if (s.empty()) return false; 
    return (s.find(input) == 0); 
} 

// ... 
// use it as follows 
n_it = names_index.equal_range("Good", comp_substr()); 
+0

Прежде всего спасибо за идею. Я добавил его к сообщению. Реализация немного отличается, потому что только std :: equal_range принимает предикаты (а не равный_режим контейнера). – Titan

+0

Какую версию Boost вы используете? Вы должны использовать 'equal_range' из упорядоченного индекса (в вашем случае). ['std :: pair equal_range (const CompatibleKey & x, const CompatibleCompare & comp) const;'] (http://www.boost.org/doc/libs/1_43_0/libs/multi_index/doc/reference/ ord_indices.html) –

+0

Мое повышение версии 1.42 – Titan

0

Вдохновленный Кириллом В Лядвинским!

Вот правильный функтор:

struct comp_substr 
{ 
    bool operator()(const char* in, const std::string s) const 
    { 
     if (s.empty()) return false; 
     return (!(s.find(in) == 0)); 
    } 
    bool operator()(const std::string s, const char* in) const 
    { 
     if (s.empty()) return false; 
     return (!(s.find(in) == 0)); 
    } 
}; 

Использования то же:

n_it = names_index.equal_range("Good", comp_substr()); 
-2
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

bool str_match(char* str,char* ser_str) 
{ 
    char *tmp = ser_str; 
    if(!str || !ser_str) 
     return 0; 
    while(*str != '\0') 
    { 
     if(*tmp != '*') 
     { 
      if(*tmp != *str) 
      { 
       str++; 
       if(*str == '\0') 
        return 0; 
       else 
        continue; 
      } 
     } 
     else 
     { 

      while(*tmp == '*') 
      { 
       tmp++; 
      } 
      if(*tmp == '\0') 
       return 1; 
      str_match(str,tmp); 
     } 

     tmp++; 
     str++; 
     if(*tmp == '\0') 
      return 1; 
    } 
    return 0; 
} 

int main(int argc, _TCHAR* argv[]) 
{ 
    char str[10][50] = {{"sdeedddd"},{"xaasass"},{"aasaddddfc"},{"wewwwwwwrrr"},{"dddddddhhhhhhh"}, 
    {"eeeeeessss"},{"asaqqqqqqqq"},{"qqqqqqqq"},{"eeeeeeeeee"},{"xaasa"}}; 
    char ser_str[50] = "*aas*"; 
    for(int i=0;i<10;++i) 
    { 
     if(str_match(str[i],ser_str)) 
     { 
      printf("%s\n",str[i]); 
     } 
    } 
    return 0; 
} 
+0

Как это отвечает на вопрос? Ваш код не решает проблему, не использует 'multi_index' и, во всех смыслах и целях, не является C++ – rlc

Смежные вопросы