C ++, как создать метод замены текста «связать» строки? - PullRequest
0 голосов
/ 02 ноября 2011

Так что я смотрю на sqlite3cpp wiki .И у них есть такой хороший API:

sqlite3pp::command cmd(db, "INSERT INTO contacts (name, phone) VALUES (:user, :phone)");
cmd.bind(":user", "Mike");
cmd.bind(":phone", "555-1234");
cmd.execute();

Интересно, как использовать boost для создания API-интерфейса для обычного std :: string?что-то вроде

std::string str = "INSERT INTO contacts (name, phone) VALUES (:user, :phone)";
bind(str, ":user", "Mike");
bind(str, ":phone", "555-1234");

Можно ли создать такую ​​вещь с помощью Boost и как это сделать?

Ответы [ 2 ]

2 голосов
/ 02 ноября 2011

Возможно: boost::algorithm::replace_all?Или, может быть, boost::algorithm::replace_all_copy, если вы не хотите изменять исходную строку.

1 голос
/ 02 ноября 2011

Заменить строку легко, но выполнить что-то, что безопасно для типов и будет хорошо преобразовывать SQL, немного по-другому. Нам нужен класс связывания, который может связываться с переданным типом и выполнять любые необходимые преобразования.

Во-первых, нам нужно обернуть std::type_info, чтобы его можно было использовать в хэш-карте:

class typeInfoWrapper
{
friend bool operator == (const typeInfoWrapper& l, const typeInfoWrapper& r);
private:
    const std::type_info& typeInfo_;

public:
    typeInfoWrapper(const std::type_info& info) : typeInfo_(info) { };

    // hasher
    class hash
    {
    public:
        size_t operator()(const typeInfoWrapper& typeInfo) const
        {
            return typeInfo.typeInfo_.hash_code();
        };
    };  // eo class hash
};  // eo class typeInfoWrapper

bool operator == (const typeInfoWrapper& l, const typeInfoWrapper& r)
{
    return l.typeInfo_.hash_code() == r.typeInfo_.hash_code();
}   // eo operator == 

Далее нам нужен сам класс. Я использую C ++ 11 здесь, поэтому я собираюсь использовать лямбды. Для каждого типа, который мы регистрируем, мы зарегистрируем функцию, которая принимает строку и возвращает ее в формате, подходящем для SQL. В этом примере я регистрирую один для строки и один для int. Строка one просто заменяет ' на '' и возвращает ее в кавычках. Int просто возвращает себя, анализ для SQL не требуется.

class binder
{
private:
    typedef std::function<std::string(std::string&)> ReplaceFunc;
    typedef std::tr1::unordered_map<typeInfoWrapper, ReplaceFunc, typeInfoWrapper::hash> ReplaceMap;
    typedef std::pair<typeInfoWrapper, ReplaceFunc> ReplacePair;
    ReplaceMap typeMap_;

public:
    binder()
    {
        // add string and int for test purposes
        typeMap_.insert(ReplacePair(typeid(const char*), [](std::string& data) -> std::string
        {
            // escape the "'" to prevent SQL injection
            boost::replace_all(data, "'", "''");
            return "'" + data + "'";
        }));

        typeMap_.insert(ReplacePair(typeid(int), [](std::string& data) -> std::string
        {
            // for sql, this is easy, just return the value as is
            return data;
        }));
    };


    // func
    template<class T>
    void bind(std::string& input, const std::string& expr, T data)
    {
        ReplaceMap::const_iterator cit(typeMap_.find(typeid(T)));
        if(cit != typeMap_.end())
            boost::replace_all(input, expr, cit->second(boost::lexical_cast<std::string>(data)));
    };  // eo bind
};  // eo class bind

И, как вы можете видеть, у нас есть функция связывания.

Теперь мы можем связывать безопасным для типов способом!

binder b;
std::string data = "SELECT * FROM table WHERE _user = :user AND _id = :id";
b.bind(data, ":user", "Moo-Juice");
b.bind(data, ":id", 32);

РЕДАКТИРОВАТЬ: исправлены некоторые ошибки.

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