简体   繁体   中英

Python style String replacement in C++

It is shown in this answer in response to its question how string replacement in Python works.

I believe it works like

string toSql(string table, string field, string value)
{
    string out;
    return out = "INSERT INTO %s (%s) VALUES (%s)" % (table,field,value);
}

Is there a similar way of doing this in C++ without file i/o?

I am trying to use this to form a query for a SQLite database.

Edit

I am avoiding using external libraries. ex Boost

Also, the inputs are supplied from the program, not the user. So i do not believe i would run into injection vulnerabilities

In the interest of answering the asked question, the idiomatic C++ way to do this is with std::ostringstream . Note that this stream class is backed by memory, not a file on disk.

(There is also the snprintf() option, which looks closer to Python string formatting but has a C-style interface and shouldn't be used from modern C++ without a good reason. If you are writing C++ then write C++, not C.)

std::string toSql(
    std::string const & table,
    std::string const & field,
    std::string const & value
) {
    std::ostringstream s;

    s << "INSERT INTO " << table
      << " (" << field << ") VALUES (" << value << ")";

    return s.str();
}

However, beware that this can open your program to SQL injection attacks if any of the arguments are unsanitized user input. You should instead use a prepared statement ( sqlite3_prepare() followed by sqlite3_bind_...() ) to bind value into the statement -- but you will still have to build the string from the table and field arguments since database object names can't be bound this way.


You can use prepared statements "the C++ way" like this (C++11 or better required for std::unique_ptr ):

#include <memory>
#include <string>
#include <sqlite3.h>

// Deleter functor to properly sqlite3_finalize() statements when we
// are done with them.
struct sqlite3_stmt_deleter
{
    void operator()(sqlite3_stmt * p) const {
        sqlite3_finalize(p);
    }
};

// Type alias for a std::unique_ptr that uses the above functor to
// clean up statements.
using sqlite3_prepared_stmt = std::unique_ptr<sqlite3_stmt, sqlite3_stmt_deleter>;

sqlite3_prepared_stmt prepare(sqlite3 * db, std::string const & sql)
{
    sqlite3_stmt * stmt = nullptr;

    // Note that we don't allow the caller to see any error information. A
    // proper wrapper will want to throw if the return isn't SQLITE3_OK.
    sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr);

    return sqlite3_prepared_stmt(stmt);
}

void example() {
    auto insert_stmt = prepare(
        your_db,
        "INSERT INTO foo (bar) VALUES (?)");

    std::string value{"baz"};

    // Bind value to the ? in the prepared statement
    sqlite3_bind_text(insert_stmt.get(), 1, value.c_str(), -1, SQLITE_TRANSIENT);

    // Execute statement.
    sqlite3_step(insert_stmt.get());

    // Reset statement so it can be used again with bind/step.
    sqlite3_reset(insert_stmt.get());

    // std::unique_ptr destructor will call sqlite3_finalize() for us.
}

Using this code, you can store a sqlite3_prepared_stmt somewhere and reuse it.

Take a look at the printf family of functions.

string toSql( string table, string field, string value )
{
  char buffer[ 100 ];
  size_t length = sprintf( buffer, "INSERT INTO %s (%s) VALUES (%s)", table.data( ), field.data( ), value.data( ) );

  if ( lenght < 0 )
  {
      //increase buffer size and try again.
  }

  printf("SQL Query = '%s'\n", buffer );

  return buffer
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM