C中的SQLite及其支持的REGEXP

C中的SQLite及其支持的REGEXP,c,regex,sqlite,C,Regex,Sqlite,我正在C中使用sqlite3,我想添加对REGEXP操作符的支持。默认情况下,用户定义的函数regexp()不存在,调用regexp通常会导致错误(根据SQLite页面) 如何添加regexp函数以支持regexp?我大概会通过sqlite3\u create\u函数调用来实现这一点,但我不知道应用程序定义的regexp()会是什么样子 我可以将regex.h中的函数与sqlite3\u create\u函数一起使用吗?如何使用?我传递给SQLite的任何函数都必须接受三个类型为sqlite3_

我正在
C
中使用
sqlite3
,我想添加对
REGEXP
操作符的支持。默认情况下,用户定义的函数
regexp()
不存在,调用
regexp
通常会导致错误(根据SQLite页面)

  • 如何添加
    regexp
    函数以支持
    regexp
    ?我大概会通过
    sqlite3\u create\u函数
    调用来实现这一点,但我不知道应用程序定义的
    regexp()
    会是什么样子

  • 我可以将
    regex.h
    中的函数与
    sqlite3\u create\u函数一起使用吗?如何使用?我传递给SQLite的任何函数都必须接受三个类型为sqlite3_context*、int、sqlite3_value**的参数。然而,SQLite文档似乎没有解释这些参数的含义

  • 是否有
    C
    regexp()
    函数的示例代码


  • 我在谷歌或SQLite页面上找不到太多关于这方面的信息。

    它看起来像这样:

    static void user_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
    {
        struct re_pattern_buffer buffer;
        const char *out;
        char *pattern;
        char *input_string;
        char *result;
        struct re_registers regs;
    
        if ((sqlite3_value_type(argv[0]) != SQLITE_TEXT )
             || ((sqlite3_value_type(argv[1]) != SQLITE_TEXT ))
        {
            sqlite3_result_err("Improper argument types");
            return;
        }
    
        re_set_syntax(RE_SYNTAX_POSIX_EGREP);
        memset(&buffer, 0, sizeof (buffer));
        if (!(pattern = strdupa(sqlite3_value_text(argv[0])))
            || !(input_string = strdupa(sqlite3_value_text(argv[1]))))
        {
            sqlite3_result_err_nomem("Could not allocate memory for strings");
            return;
        }
    
        if ((out = re_compile_pattern(pattern, strlen(pattern), &buffer))
        {
            sqlite3_result_err("Could not compile pattern!");
            return;
        }
    
        if (re_match(&buffer, input_string, strlen(input_string), 0, &regs) < 0) 
            sqlite3_result_int64(context, 0);
        else 
        {
            result = strndupa(input_string + regs.start[0], regs.end[0] - regs.start[0]);    
            sqlite3_result_text(context, result, NULL, SQLITE_TRANSIENT);
        }
    }
    
    static void user\u regexp(sqlite3\u context*context,int argc,sqlite3\u值**argv)
    {
    结构模式缓冲区;
    const char*out;
    字符*模式;
    字符*输入字符串;
    字符*结果;
    结构寄存器regs;
    如果((sqlite3值类型(argv[0])!=SQLITE文本)
    ||((sqlite3_值_类型(argv[1])!=SQLITE_文本))
    {
    sqlite3_result_err(“不正确的参数类型”);
    返回;
    }
    re_集合_语法(re_语法_POSIX_EGREP);
    memset(&buffer,0,sizeof(buffer));
    if(!(pattern=strdupa(sqlite3\u value\u text(argv[0]))
    ||!(输入字符串=strdupa(sqlite3值文本(argv[1]))
    {
    sqlite3_result_err_nomem(“无法为字符串分配内存”);
    返回;
    }
    if((out=re_compile_pattern(pattern,strlen(pattern),&buffer))
    {
    sqlite3_result_err(“无法编译模式!”);
    返回;
    }
    if(重新匹配(&buffer,输入字符串,strlen(输入字符串),0,®s)<0)
    sqlite3_result_int64(上下文,0);
    其他的
    {
    结果=strndupa(输入字符串+regs.start[0],regs.end[0]-regs.start[0]);
    sqlite3_结果_文本(上下文、结果、空、SQLITE_瞬态);
    }
    }
    
    您也可以尝试以下方法:

    #include <regex.h>
    


    好的,对此有点晚了,但是我想把这篇文章发给所有使用C++包装的人,就像我正在使用的C SQLite API一样。这个答案假设你使用SQLITCPP.

    • 从安装windows二进制文件的Regex。这将为您提供足够的文件,即
      Regex.h
      包含文件和
      regex2.dll
      。请记住在项目中添加路径Regex.h,并在包含客户端可执行文件的文件夹中保留dll的副本
    • 在构建之前,我们需要进行一些更改,将regex功能添加到
      SELECT
      查询中。为此,请从项目中打开
      数据库.cpp
      文件并

      • 包括windows正则表达式中的
        regex.h
        标题
      • 在包含所有内容之后,在下面添加一段代码(当然,您可以自定义以满足您的需要!)

        extern "C" {
        void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
        int ret;
        regex_t regex;
        char regtext[100];
        char* reg = (char*)sqlite3_value_text(values[0]);
        sprintf(regtext, ".*%s.*", reg);
        //printf("Regtext : %s", regtext);
        char* text = (char*)sqlite3_value_text(values[1]);
        /*  printf("Text : %s\n", text);
        printf("Reg : %s\n", reg); */
        if (argc != 2 || reg == 0 || text == 0) {
            sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
            return;
        }
        
        ret = regcomp(&regex, regtext, REG_EXTENDED | REG_NOSUB | REG_ICASE);
        if (ret != 0) {
            sqlite3_result_error(context, "error compiling regular expression", -1);
            return;
        }
        
        ret = regexec(&regex, text, 0, NULL, 0);
        /*  if (ret == 0) {
        printf("Found a match. Press any key to continue");
        getc(stdin);
        }*/
        regfree(&regex);
        
        sqlite3_result_int(context, (ret != REG_NOMATCH));
        }
        }
        
      • 现在是更改文件中定义的构造函数的时候了

        // Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
        Database::Database(const char* apFilename,
        const int   aFlags /*= SQLite::OPEN_READONLY*/,
        const int   aBusyTimeoutMs/* = 0 */,
        const char* apVfs/*= NULL*/) :
        mpSQLite(NULL),
        mFilename(apFilename)
        {
        const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
        //std::cout << "Reached here";
        //sqlite3_create_function_v2(mpSQLite, "REGEXP", 2, SQLITE_ANY,&sqlite_regexp, NULL, NULL, NULL,NULL);
        sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
        if (SQLITE_OK != ret)
        {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
        }
        else {
        
        }
        if (aBusyTimeoutMs > 0)
        {
        setBusyTimeout(aBusyTimeoutMs);
        }
        }
        
        // Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
        Database::Database(const std::string& aFilename,
        const int          aFlags     /*    = SQLite::OPEN_READONLY*/,
        const int          aBusyTimeoutMs/*  = 0*/,
        const std::string& aVfs/* = "" */) :
        mpSQLite(NULL),
        mFilename(aFilename)
        {
        
        const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
        sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
        if (SQLITE_OK != ret)
        {
        const SQLite::Exception exception(mpSQLite, ret); // must create before closing
        sqlite3_close(mpSQLite); // close is required even in case of error on opening
        throw exception;
        }
        if (aBusyTimeoutMs > 0)
        {
        setBusyTimeout(aBusyTimeoutMs);
        }
        }
        


      注意:这假设数据库与您的cpp在同一个文件夹中

      这里解释了用户函数的内容:@mu:谢谢,这是我第一次去的地方。当您在这里时-用户函数可以返回什么整数值?或者它们必须是空的吗?所有原型都有
      void
      返回,所以可能有这么多告诉我如何报道“真实”通过
      sqlite3\u context
      参数返回值。@mu:谢谢,我可能就快到了。看起来我必须在
      regex
      方法结束时调用
      sqlite3\u result\u int
      来通知
      SQLite
      结果。虽然我可能在这里错了。我刚刚看到这个问题出现,可能对您有用:
      extern "C" {
      void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
      int ret;
      regex_t regex;
      char regtext[100];
      char* reg = (char*)sqlite3_value_text(values[0]);
      sprintf(regtext, ".*%s.*", reg);
      //printf("Regtext : %s", regtext);
      char* text = (char*)sqlite3_value_text(values[1]);
      /*  printf("Text : %s\n", text);
      printf("Reg : %s\n", reg); */
      if (argc != 2 || reg == 0 || text == 0) {
          sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
          return;
      }
      
      ret = regcomp(&regex, regtext, REG_EXTENDED | REG_NOSUB | REG_ICASE);
      if (ret != 0) {
          sqlite3_result_error(context, "error compiling regular expression", -1);
          return;
      }
      
      ret = regexec(&regex, text, 0, NULL, 0);
      /*  if (ret == 0) {
      printf("Found a match. Press any key to continue");
      getc(stdin);
      }*/
      regfree(&regex);
      
      sqlite3_result_int(context, (ret != REG_NOMATCH));
      }
      }
      
      // Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
      Database::Database(const char* apFilename,
      const int   aFlags /*= SQLite::OPEN_READONLY*/,
      const int   aBusyTimeoutMs/* = 0 */,
      const char* apVfs/*= NULL*/) :
      mpSQLite(NULL),
      mFilename(apFilename)
      {
      const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
      //std::cout << "Reached here";
      //sqlite3_create_function_v2(mpSQLite, "REGEXP", 2, SQLITE_ANY,&sqlite_regexp, NULL, NULL, NULL,NULL);
      sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
      if (SQLITE_OK != ret)
      {
      const SQLite::Exception exception(mpSQLite, ret); // must create before closing
      sqlite3_close(mpSQLite); // close is required even in case of error on opening
      throw exception;
      }
      else {
      
      }
      if (aBusyTimeoutMs > 0)
      {
      setBusyTimeout(aBusyTimeoutMs);
      }
      }
      
      // Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
      Database::Database(const std::string& aFilename,
      const int          aFlags     /*    = SQLite::OPEN_READONLY*/,
      const int          aBusyTimeoutMs/*  = 0*/,
      const std::string& aVfs/* = "" */) :
      mpSQLite(NULL),
      mFilename(aFilename)
      {
      
      const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
      sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
      if (SQLITE_OK != ret)
      {
      const SQLite::Exception exception(mpSQLite, ret); // must create before closing
      sqlite3_close(mpSQLite); // close is required even in case of error on opening
      throw exception;
      }
      if (aBusyTimeoutMs > 0)
      {
      setBusyTimeout(aBusyTimeoutMs);
      }
      }
      
      #include <iostream>
      #include <cstdio>
      #include <cstdlib>
      #include <string>
      #include <SQLiteCpp/SQLiteCpp.h>
      #include <SQLiteCpp/VariadicBind.h>
      // Notice no sqlite3.h huh?
      // Well, this is a C++ wrapper for the SQLITE CAPI afterall.
      
      #ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
      namespace SQLite
      {
      /// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
      void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
      {
      // Print a message to the standard error output stream, and abort the program.
      std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
      std::abort();
      }
      }
      #endif
      
      /// Get example path
      static inline std::string getExamplePath()
      {
      std::string filePath(__FILE__);
      return filePath.substr(0, filePath.length() - std::string("Client.cpp").length());
      }
      
      /// Example Database
      static const std::string filename_example_db3 = getExamplePath() + "/example.db3";
      /// Image
      static const std::string filename_logo_png = getExamplePath() + "/logo.png";
      
      
      /// Object Oriented Basic example
      class Example
      {
      public:
      //Constructor
      Example() :
      mDb(filename_example_db3),
      // User change the db and tables accordingly
      mQuery(mDb, "SELECT id,name FROM lookup WHERE name REGEXP :keyword")
      // Open a database file in readonly mode
      {       
      }
      virtual ~Example()
      {
      }
      
      /// List the rows where the "weight" column is greater than the provided aParamValue
      void namehaskeyword(const std::string searchfor)
      {
      std::cout << "Matching results for " << searchfor << "\n";
      
      // Bind the integer value provided to the first parameter of the SQL query
      mQuery.bind(1,searchfor); // same as mQuery.bind(1, aParamValue);
      
       // Loop to execute the query step by step, to get one a row of results at a time
      while (mQuery.executeStep())
      {
      std::cout<<mQuery.getColumn(0) << "\t" << mQuery.getColumn(1) << "\n";
      }
      
      // Reset the query to be able to use it again later
      mQuery.reset();
      }
      
      private:
      SQLite::Database    mDb;    ///< Database connection
      SQLite::Statement   mQuery; ///< Database prepared SQL query
      };
      
      int main()
      {
      // Using SQLITE_VERSION would require #include <sqlite3.h> which we want to avoid: use SQLite::VERSION if possible.
      // std::cout << "SQlite3 version " << SQLITE_VERSION << std::endl;
      std::cout << "SQlite3 version " << SQLite::VERSION << " (" << SQLite::getLibVersion() << ")" << std::endl;
      std::cout << "SQliteC++ version " << SQLITECPP_VERSION << std::endl;
      
      try
      {
      // Doing  a regex query.
      Example example;
      char wannaquit = 'n';
      std::string keyword;
      // Deliberate unlimited loop. You implement something sensible here.
      while (wannaquit != 'y') {
      // Demonstrates the way to use the same query with different parameter values
      std::cout << "Enter the keyword to search for : ";
      std::getline(std::cin, keyword);
      example.namehaskeyword(keyword);
      }
      }
      catch (std::exception& e)
      {
      std::cout << "SQLite exception : " << e.what() << std::endl;
      return EXIT_FAILURE; // unexpected error : exit the example program
      }
      return EXIT_SUCCESS;
      }