2

I have a string that looks like this

Hello, my name is "{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 ) }}" and my title is "{{ @sql(SELECT TOP 1 title FROM table1 WHERE [id] = 5 ) }}"

I need to be able to take this string and parse out any pattern that matches the following pattern {{ @sql(WHATEVER QUERY GOES HERE) }} it must start with two braken followed by optional spaces and then @sql( ending in ) }}

Additionally, I will also need to extract the inner query which is the text that is found between @sql( and ending in ) }} Here is what I have done

$pattern = '/\{\{\s*+@sql\((.+)\)+\s*+\}\}/i';

$matches = [];

preg_match    ( $pattern, $subject, $matches, PREG_OFFSET_CAPTURE );
echo '<pre>';
print_r($matches);
echo '</pre>';

My pattern works for the following string

Hello "{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 ) }}" 

but when I need to use the pattern more than once in the text, it seems that my pattern search for the last occurrence of )}} instead of the next occurrence.

How can I update my pattern so it looks for one ore multiple matches?

Thank you

Jaylen
  • 39,043
  • 40
  • 128
  • 221
  • Possible duplicate of [PHP preg\_match and preg\_match\_all functions](http://stackoverflow.com/questions/4088836/php-preg-match-and-preg-match-all-functions) – Devon Bessemer Jun 13 '16 at 17:45
  • 1
    Have you noticed that _None_ of your sample strings like this `"{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 }}"` will match with a regex template like `{{ @sql(WHATEVER QUERY GOES HERE) }}` ? –  Jun 13 '16 at 17:48
  • Why are you using possessive quantifiers `*+` ? –  Jun 13 '16 at 17:51
  • You have to use a regex tailored to parsing sql, otherwise you can't interpret what's between `@sql(here)` –  Jun 13 '16 at 17:56
  • @sln thanks for the correction. I just updated my question again to add the `)` – Jaylen Jun 13 '16 at 18:21

3 Answers3

1

After some discussion in the comments, I guess you need preg_replace():

<?php
$string = 'Hello, my name is "{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 ) }}" and my title is "{{ @sql(SELECT TOP 1 title FROM table1 WHERE [id] = 5 ) }}"';

$regex = '~
            \{{2}\h*@sql\(    # start of outer part
            (?P<query>[^()]+) # inner query
            \)\h*\}{2}        # end of outer part
        ~x';

$string = preg_replace($regex, '$1', $string);
echo $string;
# Hello, my name is "SELECT TOP 1 name FROM table1 WHERE [id] = 5 " and my title is "SELECT TOP 1 title FROM table1 WHERE [id] = 5 "

?>

See a demo on ideone.com.

Jan
  • 42,290
  • 8
  • 54
  • 79
  • Thank you for your help. Yes, I need the inner query. I am kinds confused on how to loop over the results. also, the inner query is giving me an additional `)` at the end – Jaylen Jun 13 '16 at 18:02
  • Actually, all I am interested in is the inner query, I don't care about the rest. If it is easier just to get an array with only the inner queries that would be perfect – Jaylen Jun 13 '16 at 18:12
  • That makes more sense now. But the query is still returning an extra `)` at the end. – Jaylen Jun 13 '16 at 18:30
  • Thank you Jan. This caused another issue in index 0 which is the exact string that is found. it is missing the ending `) }}` so the query is being returned correctly but the string that is found it returnes `{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 ` instead of `{{ @sql(SELECT TOP 1 name FROM table1 WHERE [id] = 5 ) }}` I need the whole thing so I can replace the whole string found with the result of the query – Jaylen Jun 13 '16 at 20:52
  • I want to replace the string starting at `{{ @Sql(.....) }} `with the result of the inner query. I got the query and executed it with no issue. but in order to replace `{{ @Sql(.....) }}` with the query result, I need to know the whole `{{ @Sql(.....) }}` if you look at the demo you posted you will see how the ending `) }}` is removed but I need to keep it in order to replace the string correctly – Jaylen Jun 13 '16 at 21:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/114566/discussion-between-jaylen-and-jan). – Jaylen Jun 13 '16 at 21:15
0

You should just make the regex non-gready, by adding ?

...(.+?)...

(And also use preg_match_all)

nicael
  • 18,550
  • 13
  • 57
  • 90
  • Thank you for that. One thing I forgot to mention in my question "I will edit it next" is that the second index of the pattern is to extract query which is find inside the `@sql(QUERY)`. – Jaylen Jun 13 '16 at 17:52
0

One way that I do it is this: You don't want any other braces within one pair of opening and closing braces. So you can specify this:

[^\{\}]+

The above pattern will match any string of characters that does not contain a curly bracket. Your complete pattern would be

/\{\{ ?@sql\([^\{\}]+\) ?\}\}/i
  • This return the entire text starting with {{ and ending with }}. All I need to return is the query that is between `{{ @sql(` and `) }}` – Jaylen Jun 13 '16 at 18:28