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

Side by Side Diff: content/common/android/address_parser.cc

Issue 10456007: [Android] Split the address parser from AddressDetector for WebView use. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/android/address_detector.h" 5 #include "content/common/android/address_parser.h"
6 6
7 #include <bitset> 7 #include <bitset>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "net/base/escape.h" 12 #include "net/base/escape.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
14 13
15 namespace { 14 namespace {
16 15
17 // Prefix used for geographical address intent URIs.
18 static const char kAddressSchemaPrefix[] = "geo:0,0?q=";
19
20 // Maximum text length to be searched for address detection.
21 static const size_t kMaxAddressLength = 250;
22
23 // Minimum number of words in an address after the house number 16 // Minimum number of words in an address after the house number
24 // before a state is expected to be found. 17 // before a state is expected to be found.
25 // A value too high can miss short addresses. 18 // A value too high can miss short addresses.
26 const size_t kMinAddressWords = 3; 19 const size_t kMinAddressWords = 3;
27 20
28 // Maximum number of words allowed in an address between the house number 21 // Maximum number of words allowed in an address between the house number
29 // and the state, both not included. 22 // and the state, both not included.
30 const size_t kMaxAddressWords = 12; 23 const size_t kMaxAddressWords = 12;
31 24
32 // Maximum number of lines allowed in an address between the house number 25 // Maximum number of lines allowed in an address between the house number
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match) 87 if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match)
95 return false; 88 return false;
96 } 89 }
97 return *ascii_to_match == 0; 90 return *ascii_to_match == 0;
98 } 91 }
99 92
100 } // anonymous namespace 93 } // anonymous namespace
101 94
102 namespace content { 95 namespace content {
103 96
104 AddressDetector::AddressDetector() { 97 AddressParser::AddressParser() {
105 } 98 }
106 99
107 AddressDetector::~AddressDetector() { 100 bool AddressParser::FindAddress(const string16& text, string16* address) {
101 size_t start, end;
102 if (FindContent(text.begin(), text.end(), &start, &end)) {
103 address->assign(text.substr(start, end));
104 return true;
105 } else {
106 return false;
107 }
108 } 108 }
109 109
110 std::string AddressDetector::GetContentText(const string16& text) { 110 bool AddressParser::FindContent(const string16::const_iterator& begin,
111 // Get the address and replace unicode bullets with commas. 111 const string16::const_iterator& end,
112 string16 address_16 = CollapseWhitespace(text, false); 112 size_t* start_pos,
113 std::replace(address_16.begin(), address_16.end(), 113 size_t* end_pos) {
114 static_cast<char16>(0x2022), static_cast<char16>(','));
115 return UTF16ToUTF8(address_16);
116 }
117
118 GURL AddressDetector::GetIntentURL(const std::string& content_text) {
119 return GURL(kAddressSchemaPrefix +
120 net::EscapeQueryParamValue(content_text, true));
121 }
122
123 size_t AddressDetector::GetMaximumContentLength() {
124 return kMaxAddressLength;
125 }
126
127 bool AddressDetector::FindContent(const string16::const_iterator& begin,
128 const string16::const_iterator& end,
129 size_t* start_pos,
130 size_t* end_pos,
131 std::string* content_text) {
132 HouseNumberParser house_number_parser; 114 HouseNumberParser house_number_parser;
133 115
134 // Keep going through the input string until a potential house number is 116 // Keep going through the input string until a potential house number is
135 // detected. Start tokenizing the following words to find a valid 117 // detected. Start tokenizing the following words to find a valid
136 // street name within a word range. Then, find a state name followed 118 // street name within a word range. Then, find a state name followed
137 // by a valid zip code for that state. Also keep a look for any other 119 // by a valid zip code for that state. Also keep a look for any other
138 // possible house numbers to continue from in case of no match and for 120 // possible house numbers to continue from in case of no match and for
139 // state names not followed by a zip code (e.g. New York, NY 10000). 121 // state names not followed by a zip code (e.g. New York, NY 10000).
140 const string16 newline_delimiters = kNewlineDelimiters; 122 const string16 newline_delimiters = kNewlineDelimiters;
141 const string16 delimiters = kWhitespaceUTF16 + newline_delimiters; 123 const string16 delimiters = kWhitespaceUTF16 + newline_delimiters;
142 for (string16::const_iterator it = begin; it != end; ) { 124 for (string16::const_iterator it = begin; it != end; ) {
143 Word house_number; 125 Word house_number;
144 if (!house_number_parser.Parse(it, end, &house_number)) 126 if (!house_number_parser.Parse(it, end, &house_number))
145 return false; 127 return false;
146 128
147 String16Tokenizer tokenizer(house_number.end, end, delimiters); 129 String16Tokenizer tokenizer(house_number.end, end, delimiters);
148 tokenizer.set_options(String16Tokenizer::RETURN_DELIMS); 130 tokenizer.set_options(String16Tokenizer::RETURN_DELIMS);
149 131
150 std::vector<Word> words; 132 WordList words;
151 words.push_back(house_number); 133 words.push_back(house_number);
152 134
153 bool found_location_name = false; 135 bool found_location_name = false;
154 bool continue_on_house_number = true; 136 bool continue_on_house_number = true;
155 bool consecutive_house_numbers = true; 137 bool consecutive_house_numbers = true;
156 size_t next_house_number_word = 0; 138 size_t next_house_number_word = 0;
157 size_t num_lines = 1; 139 size_t num_lines = 1;
158 140
159 // Don't include the house number in the word count. 141 // Don't include the house number in the word count.
160 size_t next_word = 1; 142 size_t next_word = 1;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 tokenizer.token_end())); 238 tokenizer.token_end()));
257 } 239 }
258 240
259 // Check the parsing validity and state range of the zip code. 241 // Check the parsing validity and state range of the zip code.
260 next_word = state_last_word; 242 next_word = state_last_word;
261 if (!IsZipValid(words[zip_word], state_index)) 243 if (!IsZipValid(words[zip_word], state_index))
262 continue; 244 continue;
263 245
264 *start_pos = words[0].begin - begin; 246 *start_pos = words[0].begin - begin;
265 *end_pos = words[zip_word].end - begin; 247 *end_pos = words[zip_word].end - begin;
266 content_text->assign(GetContentText(string16(words[0].begin,
267 words[zip_word].end)));
268 return true; 248 return true;
269 } 249 }
270 } 250 }
271 } 251 }
272 252
273 // Avoid skipping too many words because of a non-address number 253 // Avoid skipping too many words because of a non-address number
274 // at the beginning of the contents to parse. 254 // at the beginning of the contents to parse.
275 if (continue_on_house_number && next_house_number_word > 0) { 255 if (continue_on_house_number && next_house_number_word > 0) {
276 it = words[next_house_number_word].begin; 256 it = words[next_house_number_word].begin;
277 } else { 257 } else {
278 DCHECK(!words.empty()); 258 DCHECK(!words.empty());
279 next_word = std::min(next_word, words.size() - 1); 259 next_word = std::min(next_word, words.size() - 1);
280 it = words[next_word].end; 260 it = words[next_word].end;
281 } 261 }
282 } 262 }
283 263
284 return false; 264 return false;
285 } 265 }
286 266
287 AddressDetector::Word::Word(const string16::const_iterator& begin, 267 AddressParser::Word::Word(const string16::const_iterator& begin,
288 const string16::const_iterator& end) 268 const string16::const_iterator& end)
289 : begin(begin), 269 : begin(begin),
290 end(end) { 270 end(end) {
291 DCHECK(begin <= end); 271 DCHECK(begin <= end);
292 } 272 }
293 273
294 bool AddressDetector::HouseNumberParser::IsPreDelimiter( 274 bool AddressParser::HouseNumberParser::IsPreDelimiter(char16 character) {
295 char16 character) {
296 return character == ':' || IsPostDelimiter(character); 275 return character == ':' || IsPostDelimiter(character);
297 } 276 }
298 277
299 bool AddressDetector::HouseNumberParser::IsPostDelimiter( 278 bool AddressParser::HouseNumberParser::IsPostDelimiter(char16 character) {
300 char16 character) {
301 return IsWhitespace(character) || strchr(",\"'", character); 279 return IsWhitespace(character) || strchr(",\"'", character);
302 } 280 }
303 281
304 void AddressDetector::HouseNumberParser::RestartOnNextDelimiter() { 282 void AddressParser::HouseNumberParser::RestartOnNextDelimiter() {
305 ResetState(); 283 ResetState();
306 for (; it_ != end_ && !IsPreDelimiter(*it_); ++it_) {} 284 for (; it_ != end_ && !IsPreDelimiter(*it_); ++it_) {}
307 } 285 }
308 286
309 void AddressDetector::HouseNumberParser::AcceptChars(size_t num_chars) { 287 void AddressParser::HouseNumberParser::AcceptChars(size_t num_chars) {
310 size_t offset = std::min(static_cast<size_t>(std::distance(it_, end_)), 288 size_t offset = std::min(static_cast<size_t>(std::distance(it_, end_)),
311 num_chars); 289 num_chars);
312 it_ += offset; 290 it_ += offset;
313 result_chars_ += offset; 291 result_chars_ += offset;
314 } 292 }
315 293
316 void AddressDetector::HouseNumberParser::SkipChars(size_t num_chars) { 294 void AddressParser::HouseNumberParser::SkipChars(size_t num_chars) {
317 it_ += std::min(static_cast<size_t>(std::distance(it_, end_)), num_chars); 295 it_ += std::min(static_cast<size_t>(std::distance(it_, end_)), num_chars);
318 } 296 }
319 297
320 void AddressDetector::HouseNumberParser::ResetState() { 298 void AddressParser::HouseNumberParser::ResetState() {
321 num_digits_ = 0; 299 num_digits_ = 0;
322 result_chars_ = 0; 300 result_chars_ = 0;
323 } 301 }
324 302
325 bool AddressDetector::HouseNumberParser::CheckFinished(Word* word) const { 303 bool AddressParser::HouseNumberParser::CheckFinished(Word* word) const {
326 // There should always be a number after a hyphen. 304 // There should always be a number after a hyphen.
327 if (result_chars_ == 0 || SafePreviousChar(it_, begin_) == '-') 305 if (result_chars_ == 0 || SafePreviousChar(it_, begin_) == '-')
328 return false; 306 return false;
329 307
330 if (word) { 308 if (word) {
331 word->begin = it_ - result_chars_; 309 word->begin = it_ - result_chars_;
332 word->end = it_; 310 word->end = it_;
333 } 311 }
334 return true; 312 return true;
335 } 313 }
336 314
337 bool AddressDetector::HouseNumberParser::Parse( 315 bool AddressParser::HouseNumberParser::Parse(
338 const string16::const_iterator& begin, 316 const string16::const_iterator& begin,
339 const string16::const_iterator& end, Word* word) { 317 const string16::const_iterator& end, Word* word) {
340 it_ = begin_ = begin; 318 it_ = begin_ = begin;
341 end_ = end; 319 end_ = end;
342 ResetState(); 320 ResetState();
343 321
344 // Iterations only used as a fail-safe against any buggy infinite loops. 322 // Iterations only used as a fail-safe against any buggy infinite loops.
345 size_t iterations = 0; 323 size_t iterations = 0;
346 size_t max_iterations = end - begin + 1; 324 size_t max_iterations = end - begin + 1;
347 for (; it_ != end_ && iterations < max_iterations; ++iterations) { 325 for (; it_ != end_ && iterations < max_iterations; ++iterations) {
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 RestartOnNextDelimiter(); 437 RestartOnNextDelimiter();
460 SkipChars(1); 438 SkipChars(1);
461 } 439 }
462 440
463 if (iterations >= max_iterations) 441 if (iterations >= max_iterations)
464 return false; 442 return false;
465 443
466 return CheckFinished(word); 444 return CheckFinished(word);
467 } 445 }
468 446
469 bool AddressDetector::FindStateStartingInWord( 447 bool AddressParser::FindStateStartingInWord(
470 WordList* words, 448 WordList* words,
471 size_t state_first_word, 449 size_t state_first_word,
472 size_t* state_last_word, 450 size_t* state_last_word,
473 String16Tokenizer* tokenizer, 451 String16Tokenizer* tokenizer,
474 size_t* state_index) { 452 size_t* state_index) {
475 453
476 // Bitmasks containing the allowed suffixes for 2-letter state codes. 454 // Bitmasks containing the allowed suffixes for 2-letter state codes.
477 static const int state_two_letter_suffix[23] = { 455 static const int state_two_letter_suffix[23] = {
478 0x02060c00, // A followed by: [KLRSZ]. 456 0x02060c00, // A followed by: [KLRSZ].
479 0x00000000, // B. 457 0x00000000, // B.
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 if (state_match) { 604 if (state_match) {
627 *state_last_word = state_word; 605 *state_last_word = state_word;
628 *state_index = state_names[state].state_index; 606 *state_index = state_names[state].state_index;
629 return true; 607 return true;
630 } 608 }
631 } 609 }
632 610
633 return false; 611 return false;
634 } 612 }
635 613
636 bool AddressDetector::IsZipValid(const Word& word, size_t state_index) { 614 bool AddressParser::IsZipValid(const Word& word, size_t state_index) {
637 size_t length = word.end - word.begin; 615 size_t length = word.end - word.begin;
638 if (length != kZipDigits && length != kZipPlus4Digits + 1) 616 if (length != kZipDigits && length != kZipPlus4Digits + 1)
639 return false; 617 return false;
640 618
641 for (string16::const_iterator it = word.begin; it != word.end; ++it) { 619 for (string16::const_iterator it = word.begin; it != word.end; ++it) {
642 size_t pos = it - word.begin; 620 size_t pos = it - word.begin;
643 if (IsAsciiDigit(*it) || (*it == '-' && pos == kZipDigits)) 621 if (IsAsciiDigit(*it) || (*it == '-' && pos == kZipDigits))
644 continue; 622 continue;
645 return false; 623 return false;
646 } 624 }
647 return IsZipValidForState(word, state_index); 625 return IsZipValidForState(word, state_index);
648 } 626 }
649 627
650 bool AddressDetector::IsZipValidForState(const Word& word, size_t state_index) { 628 bool AddressParser::IsZipValidForState(const Word& word, size_t state_index) {
651 // List of valid zip code ranges. 629 // List of valid zip code ranges.
652 static const struct { 630 static const struct {
653 char low; 631 char low;
654 char high; 632 char high;
655 char exception1; 633 char exception1;
656 char exception2; 634 char exception2;
657 } zip_range[] = { 635 } zip_range[] = {
658 { 99, 99, -1, -1 }, // AK Alaska. 636 { 99, 99, -1, -1 }, // AK Alaska.
659 { 35, 36, -1, -1 }, // AL Alabama. 637 { 35, 36, -1, -1 }, // AL Alabama.
660 { 71, 72, -1, -1 }, // AR Arkansas. 638 { 71, 72, -1, -1 }, // AR Arkansas.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 702
725 if ((zip_prefix >= zip_range[state_index].low && 703 if ((zip_prefix >= zip_range[state_index].low &&
726 zip_prefix <= zip_range[state_index].high) || 704 zip_prefix <= zip_range[state_index].high) ||
727 zip_prefix == zip_range[state_index].exception1 || 705 zip_prefix == zip_range[state_index].exception1 ||
728 zip_prefix == zip_range[state_index].exception2) { 706 zip_prefix == zip_range[state_index].exception2) {
729 return true; 707 return true;
730 } 708 }
731 return false; 709 return false;
732 } 710 }
733 711
734 bool AddressDetector::IsValidLocationName(const Word& word) { 712 bool AddressParser::IsValidLocationName(const Word& word) {
735 // Supported location names sorted alphabetically and grouped by first letter. 713 // Supported location names sorted alphabetically and grouped by first letter.
736 static const struct LocationNameInfo { 714 static const struct LocationNameInfo {
737 const char* string; 715 const char* string;
738 char length; 716 char length;
739 bool allow_plural; 717 bool allow_plural;
740 } location_names[157] = { 718 } location_names[157] = {
741 { "alley", 5, false }, { "annex", 5, false }, { "arcade", 6, false }, 719 { "alley", 5, false }, { "annex", 5, false }, { "arcade", 6, false },
742 { "ave", 3, false }, { "ave.", 4, false }, { "avenue", 6, false }, 720 { "ave", 3, false }, { "ave.", 4, false }, { "avenue", 6, false },
743 { "alameda", 7, false }, 721 { "alameda", 7, false },
744 { "bayou", 5, false }, { "beach", 5, false }, { "bend", 4, false }, 722 { "bayou", 5, false }, { "beach", 5, false }, { "bend", 4, false },
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 location_names[i].string, 814 location_names[i].string,
837 location_names[i].allow_plural)) { 815 location_names[i].allow_plural)) {
838 return true; 816 return true;
839 } 817 }
840 } 818 }
841 819
842 return false; 820 return false;
843 } 821 }
844 822
845 } // namespace content 823 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698