1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/i18n/string_search.h"
9 #include "third_party/icu/source/i18n/unicode/usearch.h"
14 FixedPatternStringSearch::FixedPatternStringSearch(const string16& find_this,
16 : find_this_(find_this) {
17 // usearch_open requires a valid string argument to be searched, even if we
18 // want to set it by usearch_setText afterwards. So, supplying a dummy text.
19 const string16& dummy = find_this_;
21 UErrorCode status = U_ZERO_ERROR;
22 search_ = usearch_open(find_this_.data(), find_this_.size(), dummy.data(),
23 dummy.size(), uloc_getDefault(),
26 if (U_SUCCESS(status)) {
27 // http://icu-project.org/apiref/icu4c40/ucol_8h.html#6a967f36248b0a1bc7654f538ee8ba96
28 // Set comparison level to UCOL_PRIMARY to ignore secondary and tertiary
29 // differences. Set comparison level to UCOL_TERTIARY to include all
30 // comparison differences.
31 // Diacritical differences on the same base letter represent a
32 // secondary difference.
33 // Uppercase and lowercase versions of the same character represents a
34 // tertiary difference.
35 UCollator* collator = usearch_getCollator(search_);
36 ucol_setStrength(collator, case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY);
37 usearch_reset(search_);
41 FixedPatternStringSearch::~FixedPatternStringSearch() {
43 usearch_close(search_);
46 bool FixedPatternStringSearch::Search(const string16& in_this,
49 bool forward_search) {
50 UErrorCode status = U_ZERO_ERROR;
51 usearch_setText(search_, in_this.data(), in_this.size(), &status);
53 // Default to basic substring search if usearch fails. According to
54 // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
55 // if either |find_this| or |in_this| are empty. In either case basic
56 // substring search will give the correct return value.
57 if (!U_SUCCESS(status)) {
58 size_t index = in_this.find(find_this_);
59 if (index == string16::npos)
64 *match_length = find_this_.size();
68 int32_t index = forward_search ? usearch_first(search_, &status)
69 : usearch_last(search_, &status);
70 if (!U_SUCCESS(status) || index == USEARCH_DONE)
73 *match_index = static_cast<size_t>(index);
75 *match_length = static_cast<size_t>(usearch_getMatchedLength(search_));
79 FixedPatternStringSearchIgnoringCaseAndAccents::
80 FixedPatternStringSearchIgnoringCaseAndAccents(const string16& find_this)
81 : base_search_(find_this, /*case_sensitive=*/false) {}
83 bool FixedPatternStringSearchIgnoringCaseAndAccents::Search(
84 const string16& in_this,
86 size_t* match_length) {
87 return base_search_.Search(in_this, match_index, match_length,
88 /*forward_search=*/true);
91 bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
92 const string16& in_this,
94 size_t* match_length) {
95 return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search(
96 in_this, match_index, match_length);
99 bool StringSearch(const string16& find_this,
100 const string16& in_this,
102 size_t* match_length,
104 bool forward_search) {
105 return FixedPatternStringSearch(find_this, case_sensitive)
106 .Search(in_this, match_index, match_length, forward_search);