C ++如何创建'bind'字符串文本替换方法?

时间:2011-11-02 07:42:34

标签: c++ string boost replace

所以我对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来创建类似于std :: string的API?意思是

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

是否有可能通过提升来创造这样的事情以及如何做到这一点?

2 个答案:

答案 0 :(得分:2)

可能:boost::algorithm::replace_all?如果您不想修改原始字符串,也可以boost::algorithm::replace_all_copy

答案 1 :(得分:1)

替换字符串很简单,但是要执行类型安全并且很好地转换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,所以我将使用lambdas。对于我们注册的每种类型,我们将注册一个函数,该函数接受一个字符串并以适合SQL的格式返回它。在这个例子中,我为一个字符串注册一个,为int注册一个。字符串1只用'替换''并将其返回引号本身。 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);

编辑:修正了一些错误。