Python和SQLite中的正则表达式问题

13 投票
3 回答
17347 浏览
提问于 2025-04-16 14:02

我想用Python在SQLite数据库中检查一个字符串是否符合某种模式,使用的是正则表达式(regex)。

我遇到的问题是,当我尝试搜索一个包含双引号(")的字符串时,正则表达式的语法就出错了。

举个例子:

cur.execute("insert into articles(id,subject) values (1,'aaa\"test\"')")
cur.execute("select id,subject from articles where id = 1")
print (cur.fetchall())

cur.execute("select subject from articles where  subject regexp '\"test\"' ")
print (cur.fetchall())

我需要在正则表达式前面加上反斜杠(\),否则编译器会报错,提示语法错误。

[(1, 'aaa"test"')]
[] <????? should found 

有人知道该怎么做吗?

我的正则表达式函数是:con.create_function("regexp", 2, regexp)

3 个回答

0

这是另一个带参数的查询示例……

在某些情况下,你可能需要自己给数据库提供一个正则表达式(REGEX)函数——我想Python的sqlite3默认情况下并不总是有这个功能。

在另一个例子中,自定义的正则表达式函数会为每一个匹配项都编译同样的表达式。其实有办法避免这种情况。下面的例子底部还有一个注释,介绍了另一种定义正则表达式操作的方法。

如果你在处理大量数据的查询时,可以通过为每个查询创建一个自定义函数,只编译一次表达式,来避免每次使用表达式时都要编译(对于每个匹配项)。在下面的代码中,self._conn是数据库连接,curs是从这个连接中获取的游标。

    # Form an expression to match nicknames with the last 3 characters
    # varying.
    nick_expr = re.sub(r"[0-9_\-|]{0,3}$", r"[0-9_\-|]{0,3}$", nick)
    nick_expr = re.compile(nick_expr, re.I)

    # Create custom sqlite3 function using the compiled expression.
    self._conn.create_function("NICKEXPR",
                               1,
                               lambda nick: nick_expr.match(nick) != None)

    # Create temporary table from first pass query.
    curs.execute(
        """ CREATE TEMP TABLE temp_table1 AS
           SELECT  DISTINCT *
           FROM    users
           WHERE   NICKEXPR(nick)
               OR  host LIKE ?
               OR  (account<>'' AND account LIKE ?)
               OR  (address<>'' AND address=?)
       """, (host, account, address))

    # Set up the REGEXP operator/function for the sqlite3 database.
    #self._conn.create_function(
    #                       'REGEXP', 2, 
    #                       lambda exp, item : re.find(exp, item) != None)
1

你可以使用三重转义符,或者用原始字符串。

你现在的做法是:

>>> print("select subject from articles where  subject regexp '\"test\"' ")
select subject from articles where  subject regexp '"test"'

使用原始字符串,也就是在字符串前面加个r,像这样r'前面有个r的字符串'

>>> print(r"select subject from articles where  subject regexp '\"test\"' ")
select subject from articles where  subject regexp '\"test\"' 

或者使用三重转义符(\\\):

>>> print("select subject from articles where  subject regexp '\\\"test\\\"' ")
select subject from articles where  subject regexp '\"test\"'
42

使用参数化的SQL语句。这样你就不需要自己去处理引号的问题了:

import sqlite3
import re

def regexp(expr, item):
    reg = re.compile(expr)
    return reg.search(item) is not None

conn = sqlite3.connect(':memory:')
conn.create_function("REGEXP", 2, regexp)
cursor = conn.cursor()
cursor.execute('CREATE TABLE foo (bar TEXT)')
cursor.executemany('INSERT INTO foo (bar) VALUES (?)',[('aaa"test"',),('blah',)])
cursor.execute('SELECT bar FROM foo WHERE bar REGEXP ?',['"test"'])
data=cursor.fetchall()
print(data)

这样就能得到

[(u'aaa"test"',)]

撰写回答