我正在尝试解析一个"插入"MySQL数据库查询,它可能看起来像这样:
insert into tablename (field1, field2, field3) values ('te''s ,, t', 3, "OO,'"P")
假设:查询始终是"合法"/没有错误的。
规则:
- 我想在
tablename
之后抓取第一个参数之间的所有字段名称
2-字段名可以包含[a-z0-9_]
,它总是跟着空格或逗号[, ]
。可以有很多空格,也可以只有一个或零个空格。
由于某些原因,它不起作用:我问"在第一个括号后找到所有 1-100 个字符的单词,后面可能有也可能不跟一个或多个逗号或空格:
preg_match_all( 'tablename '(('w{1,100}(?:[, ])*)+') values/si', $matches, $allfields );
我尝试在 PHP 中运行 preg_match_all(),它只返回最后一个字段。我错过了什么?
首先:顺便说一句,尝试使用简单/朴素的文本方法解析像SQL这样复杂的语言是一个坏主意。
关于您的特定问题,您的模式不起作用,因为您正在尝试从重复的捕获组中提取数据。重复捕获组时,上一个捕获始终被下一个捕获覆盖,依此类推。
执行此操作的模式更为复杂。这是一个经典的问题:如何在两个子字符串之间提取几个东西(重复的东西)?
执行此操作的方法需要使用与上一个结果末尾的位置匹配的'G
锚点。(注意:在开始时,由于没有先前的结果,因此'G
锚点与字符串的开头匹配。若要避免这种情况,必须使用负的预(?!'A)
以确保字符串的开头将失败。
(?:'G(?!'A)'s*,|insert's+into's+tablename's*'()'s*'K'w+
图案详情:
(?: # non capturing group with the two possible beginings
'G(?!'A) 's* , # contigous to the previous match, spaces, comma
| # OR
insert's+into's+tablename's*'( # the branch for the first result
)
's*
'K # discard all characters on the left from whole match result
'w+ # the field name
演示
当到达最后一个字段时,连续性将被破坏,因为只有一个右括号而不是逗号。所以'G
不会再成功了。
你需要使用正则表达式吗?
为此,我会使用 PHP 自己的字符串函数。
找到左括号和结束括号的位置:
$start = strpos( $sqlQuery, "(" )
$stop = strpos( $sqlQuery, ")" )
然后使用以下命令提取字段名称部分:
$names = substr($sqlQuery, $start, $stop - $start )
然后,您可以分解结果以获取每个字段名称的数组:
$nameParts = explode($names, ",")