new search query parser; support for NOT
[grauphel.git] / lib / search / queryparser.php
diff --git a/lib/search/queryparser.php b/lib/search/queryparser.php
new file mode 100644 (file)
index 0000000..7e96aaa
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Part of grauphel
+ *
+ * PHP version 5
+ *
+ * @category  Tools
+ * @package   Grauphel
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link      http://cweiske.de/grauphel.htm
+ */
+namespace OCA\Grauphel\Search;
+
+/**
+ * User search query parser
+ *
+ * @category  Tools
+ * @package   Grauphel
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @version   Release: @package_version@
+ * @link      http://cweiske.de/grauphel.htm
+ */
+class QueryParser
+{
+    /**
+     * Splits the user's query string up into several keywords
+     * that all have to be within or not appear in the note (AND, NOT).
+     *
+     * Split by space, quotes are supported:
+     * - foo bar
+     *   -> searches for notes that contain "foo" and "bar"
+     * - foo "bar baz"
+     *   -> searches for notes that contain "foo" and "bar baz"
+     *
+     * Exclusion is supported:
+     * - foo -bar
+     *   -> search for notes that contain "foo" but not "bar"
+     * - foo -"bar baz"
+     *   -> search for notes that contain "foo" but not "bar baz"
+     *
+     * @param string $query User-given query string
+     *
+     * @return array Array of keyword arrays, grouped by "AND" and "NOT"
+     */
+    public function parse($query)
+    {
+        $keywords = array();
+        $query    = trim($query);
+
+        $groupMap = array(
+            '+' => 'AND',
+            '-' => 'NOT',
+        );
+
+        $chQuote    = null;
+        $curKeyword = '';
+        $group      = 'AND';
+        foreach (str_split($query) as $char) {
+            if ($char == '"' || $char == '\'') {
+                if ($chQuote === null) {
+                    //new quote
+                    $chQuote = $char;
+                    continue;
+                } else if ($char == $chQuote) {
+                    //quote end
+                    if (strlen($curKeyword)) {
+                        $keywords[$group][] = $curKeyword;
+                        $curKeyword = '';
+                    }
+                    $chQuote = null;
+                    continue;
+                }
+            } else if ($char == ' ' && $chQuote === null) {
+                if (strlen($curKeyword)) {
+                    $keywords[$group][] = $curKeyword;
+                    $curKeyword = '';
+                    $group = 'AND';
+                }
+                continue;
+            } else if ($char == '+' || $char == '-' && $curKeyword == '') {
+                $group = $groupMap[$char];
+                continue;
+            }
+
+            $curKeyword .= $char;
+        }
+        if (strlen($curKeyword)) {
+            $keywords[$group][] = $curKeyword;
+        }
+        return $keywords;
+    }
+
+}
+?>