【问题标题】:To parse SQL with regex, excluding quoted literals使用正则表达式解析 SQL,不包括引用的文字
【发布时间】:2026-01-02 08:35:01
【问题描述】:

对于我的 DBAL,我需要解析提供的 SQL [mysql 方言,特别是] 字符串以查找所有占位符。

但是,当然,我不想解析任何类似占位符的组合,这些组合偶尔可能出现在带引号的文字内部——单引号或双引号或反引号。

说,可能是

SELECT amount as `Amount: boxes` FROM t WHERE q='howdy?' and a='I\'m OK' and category=?

只有最后一个问号是唯一的实际占位符

鉴于大量的转义规则,其中一些取决于当前的数据库设置(NO_BACKSLASH_ESCAPESANSI_QUOTES 等),这可以将上述查询变成

SELECT amount as "Amount:boxes" FROM t WHERE q='howdy?' and a='I''m OK' and category=?

我怀疑任务是否可行。

但是,我仍然希望它可以完成,并且可能有人甚至手头有解决方案。

【问题讨论】:

  • 对于这项任务来说可能太大了,但您是否考虑过 code.google.com/p/php-sql-parser 而不是正则表达式?
  • 我把它作为最后的手段。当然不是像这样的完整 SQL 解析器,但原理相同。然而,似乎 NikiC 处理了它

标签: php mysql regex parsing


【解决方案1】:

您要查找的一般模式是/string(*SKIP)(*F)|\?/,其中string 是匹配字符串的正则表达式。我对 SQL 字符串语法并不十分熟悉。一些建议:

  • 带反斜杠转义的单引号:'[^'\\]*(?:\\.[^'\\]*)*'
  • 带引号重复转义的单引号:'[^']*(?:''[^']*)*'

例如带有反斜杠和重复转义的单引号、双引号和反引号的完整正则表达式可能如下所示:

/(?:
    '[^'\\]*(?:(?:\\.|'')[^'\\]*)*'
  | "[^"\\]*(?:(?:\\.|"")[^"\\]*)*"
  | `[^`\\]*(?:(?:\\.|``)[^`\\]*)*`
 )(*SKIP)(*F)| \?
/x

将其与preg_match_allpreg_replace_callback 匹配,具体取决于您想要什么。

注意:为避免额外的转义,请将正则表达式放在 NOWDOC 字符串中。

【讨论】:

  • @AmalMurali 我添加了双引号和反引号
  • 我看到了更新,并且已经 +1 了 :) 这是一个有效的演示:eval.in/116177
  • 呃。谢谢 Nikita(以及 @Amal 的演示)。我不得不承认我几乎无法破译这种模式(这里是一个困惑的笑脸),但它确实有效!好的答案总能让你学到更多,而这个答案就是这样。
  • @YourCommonSense:请注意,此操作需要在完全了解数据库连接上使用的字符编码的情况下执行。当然,在 PHP 中,“PCRE”模式可以是 modified 以使用 PCRE_UTF8 模式,但这仍然只是众多可能的字符编码之一......而且由于 PHP 在其多字节扩展中不提供与 perl 兼容的正则表达式。 .. 遗憾的是,我在这里看不到一个简单的通用解决方案。如果需要,也许您的 safeMySQL 可以在连接上强制使用 UTF-8 并在 PHP 中转码?
  • @eggyal 我宁愿将所有标识符都明确列入白名单