1

I have a form input field 'text' and I want to create different query depending on value put in that field by a user

  1. if the there is just a phrase - search each word (f.e. 'Hello World'):

    SELECT (...) WHERE x LIKE '%Hello%' AND x LIKE '%World%' etc...
    
  2. if the phrase is in quotation marks - search whole phrase (f.e. '"Hello World"'):

    SELECT (...) WHERE x LIKE '%Hello World%'
    

And that's cool - I can do that.

But my problem starts when I have to mix above functionality - so f.e. if the phrase is 'Hello World "my name is" John' - it should search like this:

SELECT (...) 
WHERE x LIKE '%Hello%' 
    AND x LIKE '%World%' 
    AND x LIKE '%my name is%' 
    AND x LIKE '%John%'

How would You implement such functionality and manage to do that in php?

Machavity
  • 30,841
  • 27
  • 92
  • 100

2 Answers2

2

You could use a preg_match_all(...):

$text = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing \\"elit" dolor';
preg_match_all('/"(?:\\\\.|[^\\\\"])*"|\S+/', $text, $matches);
print_r($matches);

which will produce:

Array
(
    [0] => Array
        (
            [0] => Lorem
            [1] => ipsum
            [2] => "dolor sit amet"
            [3] => consectetur
            [4] => "adipiscing \"elit"
            [5] => dolor
        )

)

And as you can see, it also accounts for escaped quotes inside quoted strings.

A short explanation:

"           # match the character '"'
(?:         # start non-capture group 1 
  \\        #   match the character '\'
  .         #   match any character except line breaks
  |         #   OR
  [^\\"]    #   match any character except '\' and '"'
)*          # end non-capture group 1 and repeat it zero or more times
"           # match the character '"'
|           # OR
\S+         # match a non-whitespace character: [^\s] and repeat it one or more times

And in case of matching %22 instead of double quotes, you'd do:

preg_match_all('/%22(?:\\\\.|(?!%22).)*%22|\S+/', $text, $matches);

You can check this also

Community
  • 1
  • 1
CardCaptor
  • 390
  • 1
  • 5
  • 13
0

You can use preg_replace() and preg_split() within preg_replace_callback with a few declared variables to build up your Query. The Code Snippet below shows how:

<?php

    $str        = 'Hello World, "My Name is" and "her name is"';
    $matches    = array();
    $result     = preg_replace_callback("#\".*?\"#", function($match) use(&$matches, &$str) {
        $matches[]  = trim($match[0], ",.:?;\"");
        $res        = preg_split("#\s.*?#", preg_replace("#\".*?\"#", "", $str));
        $matches    = array_merge($matches, $res);
        $matches    = array_unique(array_filter(array_merge($matches, $res)));
    }, $str);

    $query      = "SELECT * FROM `tbl_name` AS tbl WHERE ";
    foreach($matches as $searchTerm){
        $query .= " tbl.x LIKE '%" . $searchTerm . "%' OR ";
    }
    $query      = rtrim($query, " OR ");


    var_dump($query);
    var_dump($matches);
The 2 var_dumps() above: var_dump($query) and var_dump($matches) respectively produces:
    string 'SELECT * FROM `tbl_name` AS tbl WHERE  tbl.x LIKE '%My Name is%' OR  tbl.x LIKE '%Hello%' OR  tbl.x LIKE '%World,%' OR  tbl.x LIKE '%and%' OR  tbl.x LIKE '%her name is%'' (length=169)

    array (size=5)
      0 => string 'My Name is' (length=10)
      1 => string 'Hello' (length=5)
      2 => string 'World,' (length=6)
      3 => string 'and' (length=3)
      4 => string 'her name is' (length=11)
Poiz
  • 7,611
  • 2
  • 15
  • 17