C++如何创建"绑定"字符串文本替换方法?

C++ how to create 'bind' string text replacement method?

本文关键字:绑定 字符串 方法 文本替换 何创建 创建 C++      更新时间:2023-10-16

所以我看一下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");

有可能用boost创建这样的东西吗?怎么做?

可能:boost::algorithm::replace_all ?或者boost::algorithm::replace_all_copy,如果你不想修改原始字符串

替换字符串很容易,但要执行类型安全的操作并很好地转换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,所以我要用lambda。对于我们注册的每种类型,我们将注册一个函数,该函数接受字符串并以适合SQL的格式返回字符串。在本例中,我分别为字符串和int类型注册了一个。字符串一个只是用''替换',并返回引号本身。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

如你所见,我们有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);