PHP正则表达式:在2个括号中找到许多单词

时间:2015-06-17 00:27:23

标签: php regex

我试图解析"插入" MySQL数据库查询可能如下所示:

insert into tablename (field1,   field2, field3) values ('te\'s ,, t', 3, "OO,\"P")

假设:查询始终是合法的' /没有错。

规则:

  1. 我想在tablename
  2. 之后第一个 paranthese之间抓取所有字段名称

    2-字段名称可以包含[a-z0-9_]始终后跟空格或逗号[, ]。可能有很多空格或只有一个或零个。

    由于某些原因,它不起作用:我要求"在第一个括号后找到1-100个字符的所有单词,可能会或不会出现一个或多个昏迷或空格:

    preg_match_all( 'tablename \((\w{1,100}(?:[, ])*)+\) values/si', $matches, $allfields );
    

    我尝试在PHP中运行preg_match_all()并返回 last 字段。我错过了什么?

2 个答案:

答案 0 :(得分:2)

首先:顺便说一句,尝试使用简单/朴素的文本方法解析像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

demo

当到达最后一个字段时,连续性被打破,因为只有一个右括号而不是逗号。所以\G将不再成功。

答案 1 :(得分:0)

您需要使用正则表达式吗?

我会使用PHP自己的String函数。

找到开始和结束括号的位置:

$start = strpos( $sqlQuery, "(" )
$stop = strpos( $sqlQuery, ")" )

然后使用以下内容提取字段名称部分:

$names = substr($sqlQuery, $start, $stop - $start )

然后,您可以展开结果以获取每个字段名称的数组:

$nameParts = explode($names, ",")