Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: chrome/browser/history/query_parser.cc

Issue 9316129: Don't strip punctuation inside quotes in history search queries. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/browser/history/query_parser_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/history/query_parser.cc
diff --git a/chrome/browser/history/query_parser.cc b/chrome/browser/history/query_parser.cc
index 9fafc9bf1b29c3a189a2719e362ea38917ff58e5..4005e378d98498f75aae64d2c68cdb7393d4f509 100644
--- a/chrome/browser/history/query_parser.cc
+++ b/chrome/browser/history/query_parser.cc
@@ -11,6 +11,7 @@
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/stl_util.h"
+#include "base/string_util.h"
namespace {
@@ -46,7 +47,7 @@ void CoalesceMatchesFrom(size_t index, Snippet::MatchPositions* matches) {
// Sorts the match positions in |matches| by their first index, then coalesces
// any match positions that intersect each other.
-void CoalseAndSortMatchPositions(Snippet::MatchPositions* matches) {
+void CoalesceAndSortMatchPositions(Snippet::MatchPositions* matches) {
std::sort(matches->begin(), matches->end(), &CompareMatchPosition);
// WARNING: we don't use iterator here as CoalesceMatchesFrom may remove
// from matches.
@@ -64,6 +65,13 @@ bool IsQueryQuote(wchar_t ch) {
ch == 0x201e; // double low-9 quotation mark
}
+// Returns true if the character is considered non-breaking when it appears in
+// the middle of a word. This can be used to prevent an URL-like query from
+// being broken into multiple words.
+bool IsNonBreakingSymbol(wchar_t ch) {
+ return ch == '.' || ch == '-';
+}
+
} // namespace
// Inheritance structure:
@@ -71,7 +79,8 @@ bool IsQueryQuote(wchar_t ch) {
// QueryNodes are either a collection of subnodes (a QueryNodeList)
// or a single word (a QueryNodeWord).
-// A QueryNodeWord is a single word in the query.
+// A QueryNodeWord is a sequence of consecutive characters in a query.
+// It can be an actual word or an URL-like sequence of characters.
class QueryNodeWord : public QueryNode {
public:
explicit QueryNodeWord(const string16& word);
@@ -80,6 +89,7 @@ class QueryNodeWord : public QueryNode {
const string16& word() const { return word_; }
void set_literal(bool literal) { literal_ = literal; }
+ void Append(const string16& word);
Scott Hess - ex-Googler 2013/04/17 18:14:02 I think this sense of "Append" is enough different
// QueryNode:
virtual int AppendToSQLiteQuery(string16* query) const OVERRIDE;
@@ -103,6 +113,10 @@ QueryNodeWord::QueryNodeWord(const string16& word)
QueryNodeWord::~QueryNodeWord() {}
+void QueryNodeWord::Append(const string16& str) {
+ word_ += str;
+}
+
int QueryNodeWord::AppendToSQLiteQuery(string16* query) const {
query->append(word_);
@@ -348,7 +362,7 @@ bool QueryParser::DoesQueryMatch(const string16& text,
// completely punt here.
match_positions->clear();
} else {
- CoalseAndSortMatchPositions(&matches);
+ CoalesceAndSortMatchPositions(&matches);
match_positions->swap(matches);
}
return true;
@@ -366,27 +380,45 @@ bool QueryParser::ParseQueryImpl(const string16& query, QueryNodeList* root) {
query_stack.push_back(root);
bool in_quotes = false; // whether we're currently in a quoted phrase
+ QueryNodeWord* current_word = NULL;
while (iter.Advance()) {
// Just found a span between 'prev' (inclusive) and 'pos' (exclusive). It
- // is not necessarily a word, but could also be a sequence of punctuation
- // or whitespace.
- if (iter.IsWord()) {
- QueryNodeWord* word_node = new QueryNodeWord(iter.GetString());
- if (in_quotes)
- word_node->set_literal(true);
- query_stack.back()->AddChild(word_node);
- } else { // Punctuation.
- if (IsQueryQuote(query[iter.prev()])) {
- if (!in_quotes) {
- QueryNodeList* quotes_node = new QueryNodePhrase;
- query_stack.back()->AddChild(quotes_node);
- query_stack.push_back(quotes_node);
- in_quotes = true;
- } else {
- query_stack.pop_back(); // Stop adding to the quoted phrase.
- in_quotes = false;
- }
+ // is not necessarily a word, it could also be a punctuation or whitespace
+ // character. Punctuation is preserved inside quotes, and otherwise removed
+ // except if it is a non-breaking character in the middle of a word.
+
+ wchar_t first_char = query[iter.prev()];
+ if (IsQueryQuote(first_char)) {
+ if (!in_quotes) {
+ QueryNodeList* quotes_node = new QueryNodePhrase;
+ query_stack.back()->AddChild(quotes_node);
+ query_stack.push_back(quotes_node);
+ in_quotes = true;
+ } else {
+ query_stack.pop_back(); // Stop adding to the quoted phrase.
+ in_quotes = false;
+ }
+ current_word = NULL;
+ } else if (iter.IsWord() || (in_quotes && !IsWhitespace(first_char))) {
Scott Hess - ex-Googler 2013/04/17 18:14:02 Previously, if there were a sequence of IsWord() t
+ // Append to the current word if the new token is a word or a non-
+ // whitespace token inside quotes.
+ if (current_word) {
+ current_word->Append(iter.GetString());
+ } else {
+ current_word = new QueryNodeWord(iter.GetString());
+ current_word->set_literal(in_quotes);
+ query_stack.back()->AddChild(current_word);
}
+ } else if (current_word != NULL) {
+ // Allow non-breaking symbols inside a word.
+ // Any other punctuation or whitespace character ends the current word.
+
+ // TODO(dubroy): Consider sharing code with the omnibox to allow a more
+ // accurate "best guess" of whether a sequence of characters is a URL.
+ if (IsNonBreakingSymbol(first_char))
+ current_word->Append(iter.GetString());
Scott Hess - ex-Googler 2013/04/17 18:14:02 I believe this won't back out the symbol(s) if the
+ else
+ current_word = NULL;
}
}
« no previous file with comments | « no previous file | chrome/browser/history/query_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698