我想用php正则表达式分析一个mysql请求, 也就是说,从mysql语句中提取select_expr和table_references。 例如,这里有两个我希望我的正则表达式匹配的mysql查询:
select id, name from table
select id, name
从该查询中我想提取两部分:“id,name”信息和“table”信息。
第一部分实际上可以包含一个字符串,如CONCAT('id','。','nom')AS别名,
,第二部分看起来像:table t INNER JOIN table2 t2 ON t.id = t2.user_id。
所以我试过这个“我知道它不起作用但会让我上路”正则表达式:
'!select (.*)( from (.*))?!i'
当然,第一个捕捉括号直到结束,这不是我想要的。
在
中select id, name from table
字符串,它匹配“id,nom from table”作为第一部分,这不是我想要的。 (我希望“id,nom”作为第一部分,“table”作为第二部分)。
从这一点来说,我想做的是告诉正则表达式第一个捕获括号 如果成立,则不应与“from”序列匹配。 我知道有一个否定的字符类功能,[^ a-z], 但这只是否定一个字符而不是一个完整的字符串(按正确顺序排列的字母序列)。
你有这个灯吗? 我们可以否定括号的内容,例如使用正则表达式吗?
答案 0 :(得分:1)
最后一点,如果你的问题听起来像你的查询中的'from'部分是可选的,是吗?
如果是这样,那就试试这个:
!^select (.*?)(?: from (.*))?$!i
这将匹配“select”和“from”之间的所有内容,如果找到“from”,否则它将匹配“select”之后的所有内容。
加入?在“。*?”它告诉'*'不要贪婪,所以当它碰到表达式的其余部分匹配的地方时,它不会继续占用更多的字符。 我还添加了'?:',这使得第二组成为非捕获组,因为没有有用的信息可以从中读取。最后将表达式包装在^和$中以标记行的开始和结束。
如果'from'不是可选的,那么它就容易多了,你可以使用它:
!^select (.*) from (.*)$!i
答案 1 :(得分:0)
问题是你使用greedy matching。也就是说,您的第一个.*
组会匹配字符,直到您的正则表达式的其余部分中断。由于FROM
子句是可选的,因此它永远不会发生,并且您的第一个组只匹配所有内容。解决方案是使用非贪婪匹配,在?
之后添加*
(它也适用于+
)。
'!select (.*?)( from (.*))?!i'
对于你的简单案例应该足够了。但是,如果要解析整个查询,那么向后解析SQL语句实际上要容易得多。例如,让我们有一个功能齐全的SQL查询:
SELECT foo FROM bar WHERE cond GROUP BY col HAVING stuff ORDER BY this
如果你strrev
,你得到:
siht YB REDRO ffuts GNIVAH loc YB PUORG dnoc EREHW rab MORF oof TCELES
考虑到这一点,您可以使用正则表达式轻松地将其拆分,而不会以LISPesque数量的堆叠括号结束。这是我用来匹配这样一个字符串的注释正则表达式(你需要把它放回一行没有空格)。
^ // match the beginning
(.+\s+YB\s*REDRO)?\s* // is there an ORDER BY?
(.+\s+GNIVAH)?\s* // is there a HAVING?
(.+\s+YB\s*PUORG)?\s* // is there a GROUP BY?
(.+\s+EREHW)?\s* // is there a WHERE?
(.+\s+MORF)?\s* // is there a FROM?
.+\s+TCELES // there is a SELECT
$ // match the end
现在,你所要做的只是strrev
支持你的结果,并且瞧!你有一个很好的分裂查询。
编辑我们可以使用非捕获组和命名组来增强正则表达式。现在,我们通过比赛获得个别条款;也就是说,它们以关键字开头。如果没有关键字,告诉捕获组中的内容会非常混乱。命名组有助于解决此问题。
非捕获组是未出现在正则表达式结果中的组。它们以?:
开头,它们对于使块可选(如(?:stuff here)?
)非常有用,而无需在结果中处理它。
这是新的正则表达式。我也只是learned about the x
modifier这使得PCRE忽略空格并接受正则表达式中的注释,所以让我们用它来制作一个有效的片段。
$regex = "/^
(?:(?<orderby>.+)\s+YB\s*REDRO)?\s* # is there an ORDER BY?
(?:(?<having>.+)\s+GNIVAH)?\s* # is there a HAVING?
(?:(?<groupby>.+)\s+YB\s*PUORG)?\s* # is there a GROUP BY?
(?:(?<where>.+)\s+EREHW)?\s* # is there a WHERE?
(?:(?<from>.+)\s+MORF)?\s* # is there a FROM?
(?<select>.+)\s+TCELES # there is a SELECT
$/msix";
$query = "SELECT foo FROM bar WHERE cond GROUP BY col HAVING stuff ORDER BY this";
preg_match($regex, strrev($query), $matches);
foreach ($matches as &$match)
$match = strrev($match);
// now we can use $matches['from'] to get the FROM clause
echo $matches['from'];
print_r($matches);
答案 2 :(得分:0)
试试这个:
$string = "select id, name, CONCAT('id','.','nom') AS alias as a from table t INNER JOIN table2 t2 ON t.id=t2.user_id";
preg_match_all("!select (.*) from (.*)!i", $string, $result);
var_dump($result);
我刚试过它,它运作得很好。