正则表达式,PHP:如何否定一个捕获括号
我想分析一个MySQL正则表达式的请求, ,即从mysql语句中提取select_expr和table_references。 例如,这里有两个,我想我的正则表达式匹配的MySQL查询:正则表达式,PHP:如何否定一个捕获括号
select id, name from table
select id, name
从该查询我想提取2个部分:“ID,名称为”信息和“表”信息太多。
第一部分实际上可以包含像CONCAT一个字符串( 'ID', 'NOM' '')AS别名,
和第二部分可以是这样的:表t INNER JOIN table2的T2 ON吨.ID = t2.user_id。
所以,我想这个“我知道这不是工作,但会让我在路上”的正则表达式:
'!select (.*)(from (.*))?!i'
当然,上述第一捕捉括号得到所有,直到最后,这是不是我想。
在
select id, name from table
字符串,它匹配“从表ID,NOM”的第一部分,这不是我想要的。 (我想在这种情况下第一部分是“id,nom”,第二部分是“table”)。
从这一点我想要做的是告诉正则表达式,如果创建,第一个捕获括号 不应该匹配“从”序列。 我知道有否定字符类功能,[^ a-z], ,但它只是否定一个字符而不是整个字符串(作为按正确顺序的字母序列)。
你有什么灯光吗? 我们可以用正则表达式否定括号内容吗?
问题是您使用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);
尝试了这一点:
$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);
我只是测试它,它工作得很好。
它不适用于'select id,name',这是OP想要解析的查询的第二个例子 – zneak
最后一点,如果你的问题听起来像你的查询的'从'部分是可选的,是吗?
如果是的话,那就试试这个:
!^select (.*?)(?: from (.*))?$!i
这将匹配之间的“选择”和“从”,如果“从”被发现,否则它只会匹配后一切“选择”的一切。
通过添加?在“。*?”中它告诉'*'不要贪婪,所以当它碰到一个表达式匹配的地方时,它不会继续占用更多的字符。 我还添加了'?:',这使得第二组成为非捕获组,因为没有有用的信息可以从中读取。最后在^和$中包装表达式来标记行的开始和结束。
如果 '从' 是不可选的,虽然,那么它是一个极大的方便,你可以用这个!(。*?)。
!^select (.*) from (.*)$!i
谢谢,这是一个我在寻找 – ling
是” ^选择(?:从(*) )?$!我工作? – loganfsmyth
哦,是的,谢谢,我会调查那个(?:)符号。真的很酷。 – ling