query-parser: support phrase queries
This commit is contained in:
@ -118,11 +118,10 @@ static void
|
|||||||
test_escape ()
|
test_escape ()
|
||||||
{
|
{
|
||||||
CaseVec cases = {
|
CaseVec cases = {
|
||||||
{ "foo\"bar\"", Tokens{Token{3, TT::Data, "foo"},
|
{ "foo\"bar\"", Tokens{Token{8, TT::Data, "foobar"}}},
|
||||||
Token{8, TT::Data, "bar"}}},
|
|
||||||
{ "\"fnorb\"", Tokens{Token{7, TT::Data, "fnorb"}}},
|
{ "\"fnorb\"", Tokens{Token{7, TT::Data, "fnorb"}}},
|
||||||
{ "\\\"fnorb\\\"", Tokens{Token{9, TT::Data, "\"fnorb\""}}},
|
{ "\\\"fnorb\\\"", Tokens{Token{9, TT::Data, "fnorb"}}},
|
||||||
{ "foo\\\"bar\\\"", Tokens{Token{10, TT::Data, "foo\"bar\""}}}
|
{ "foo\\\"bar\\\"", Tokens{Token{10, TT::Data, "foobar"}}}
|
||||||
};
|
};
|
||||||
|
|
||||||
test_cases (cases);
|
test_cases (cases);
|
||||||
|
|||||||
@ -27,12 +27,11 @@ using namespace Mux;
|
|||||||
static bool
|
static bool
|
||||||
is_separator (char c)
|
is_separator (char c)
|
||||||
{
|
{
|
||||||
const auto seps = std::string (":()\"");
|
|
||||||
|
|
||||||
if (isblank(c))
|
if (isblank(c))
|
||||||
return true;
|
return true;
|
||||||
else
|
|
||||||
return seps.find(c) != std::string::npos;
|
const auto seps = std::string ("()");
|
||||||
|
return seps.find(c) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -80,8 +79,14 @@ eat_token (std::string& food, size_t& pos)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kar == '"' && !escaped && quoted)
|
if (kar == '"') {
|
||||||
return Token{pos, Token::Type::Data, value};
|
if (!escaped && quoted)
|
||||||
|
return Token{pos, Token::Type::Data, value};
|
||||||
|
else {
|
||||||
|
quoted = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!quoted && !escaped && is_separator(kar)) {
|
if (!quoted && !escaped && is_separator(kar)) {
|
||||||
|
|
||||||
@ -90,9 +95,6 @@ eat_token (std::string& food, size_t& pos)
|
|||||||
return op_or_value(pos, value);
|
return op_or_value(pos, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kar == '"')
|
|
||||||
quoted = true;
|
|
||||||
|
|
||||||
if (quoted || isblank(kar))
|
if (quoted || isblank(kar))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@ -110,6 +110,20 @@ Mux::utf8_flatten (const std::string& str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string>
|
||||||
|
Mux::split (const std::string& str, const std::string& sepa)
|
||||||
|
{
|
||||||
|
char **parts = g_strsplit(str.c_str(), sepa.c_str(), -1);
|
||||||
|
std::vector<std::string> vec;
|
||||||
|
for (auto part = parts; part && *part; ++part)
|
||||||
|
vec.push_back (*part);
|
||||||
|
|
||||||
|
g_strfreev(parts);
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
Mux::quote (const std::string& str)
|
Mux::quote (const std::string& str)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#ifndef __UTILS_HH__
|
#ifndef __UTILS_HH__
|
||||||
#define __UTILS_HH__
|
#define __UTILS_HH__
|
||||||
@ -33,6 +34,17 @@ namespace Mux {
|
|||||||
*/
|
*/
|
||||||
std::string utf8_flatten (const std::string& str);
|
std::string utf8_flatten (const std::string& str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a string in parts
|
||||||
|
*
|
||||||
|
* @param str a string
|
||||||
|
* @param sepa the separator
|
||||||
|
*
|
||||||
|
* @return the parts.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> split (const std::string& str,
|
||||||
|
const std::string& sepa);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quote & escape a string
|
* Quote & escape a string
|
||||||
*
|
*
|
||||||
|
|||||||
@ -48,6 +48,35 @@ xapian_query_op (const Mux::Tree& tree)
|
|||||||
return Xapian::Query(op, childvec.begin(), childvec.end());
|
return Xapian::Query(op, childvec.begin(), childvec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Xapian::Query
|
||||||
|
xapian_query_value (const Mux::Tree& tree)
|
||||||
|
{
|
||||||
|
const auto v = dynamic_cast<Value*> (tree.node.data.get());
|
||||||
|
const auto parts = split (v->value, " ");
|
||||||
|
|
||||||
|
std::vector<Xapian::Query> phvec;
|
||||||
|
for (const auto p: parts)
|
||||||
|
phvec.push_back(Xapian::Query(v->prefix + p));
|
||||||
|
|
||||||
|
if (parts.empty())
|
||||||
|
return Xapian::Query::MatchNothing; // shouldn't happen
|
||||||
|
|
||||||
|
if (parts.size() == 1)
|
||||||
|
return phvec.front();
|
||||||
|
|
||||||
|
return Xapian::Query (Xapian::Query::OP_PHRASE,
|
||||||
|
phvec.begin(), phvec.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Xapian::Query
|
||||||
|
xapian_query_range (const Mux::Tree& tree)
|
||||||
|
{
|
||||||
|
const auto r = dynamic_cast<Range*> (tree.node.data.get());
|
||||||
|
return Xapian::Query(Xapian::Query::OP_VALUE_RANGE,
|
||||||
|
(Xapian::valueno)r->id, r->lower, r->upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Xapian::Query
|
Xapian::Query
|
||||||
Mux::xapian_query (const Mux::Tree& tree)
|
Mux::xapian_query (const Mux::Tree& tree)
|
||||||
{
|
{
|
||||||
@ -60,15 +89,10 @@ Mux::xapian_query (const Mux::Tree& tree)
|
|||||||
case Node::Type::OpXor:
|
case Node::Type::OpXor:
|
||||||
case Node::Type::OpAndNot:
|
case Node::Type::OpAndNot:
|
||||||
return xapian_query_op (tree);
|
return xapian_query_op (tree);
|
||||||
case Node::Type::Value: {
|
case Node::Type::Value:
|
||||||
const auto v = dynamic_cast<Value*> (tree.node.data.get());
|
return xapian_query_value (tree);
|
||||||
return Xapian::Query(v->prefix + v->value);
|
case Node::Type::Range:
|
||||||
}
|
return xapian_query_range (tree);
|
||||||
case Node::Type::Range: {
|
|
||||||
const auto r = dynamic_cast<Range*> (tree.node.data.get());
|
|
||||||
return Xapian::Query(Xapian::Query::OP_VALUE_RANGE,
|
|
||||||
(Xapian::valueno)r->id, r->lower, r->upper);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error ("invalid query"); // bug
|
throw std::runtime_error ("invalid query"); // bug
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user