string_search.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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.
4
5#include "base/i18n/string_search.h"
6#include "base/logging.h"
7
8#include "third_party/icu/public/i18n/unicode/usearch.h"
9
10namespace base {
11namespace i18n {
12
13FixedPatternStringSearchIgnoringCaseAndAccents::
14FixedPatternStringSearchIgnoringCaseAndAccents(const string16& find_this)
15    : find_this_(find_this) {
16  // usearch_open requires a valid string argument to be searched, even if we
17  // want to set it by usearch_setText afterwards. So, supplying a dummy text.
18  const string16& dummy = find_this_;
19
20  UErrorCode status = U_ZERO_ERROR;
21  search_ = usearch_open(find_this_.data(), find_this_.size(),
22                         dummy.data(), dummy.size(),
23                         uloc_getDefault(),
24                         NULL,  // breakiter
25                         &status);
26  if (U_SUCCESS(status)) {
27    UCollator* collator = usearch_getCollator(search_);
28    ucol_setStrength(collator, UCOL_PRIMARY);
29    usearch_reset(search_);
30  }
31}
32
33FixedPatternStringSearchIgnoringCaseAndAccents::
34~FixedPatternStringSearchIgnoringCaseAndAccents() {
35  if (search_)
36    usearch_close(search_);
37}
38
39bool FixedPatternStringSearchIgnoringCaseAndAccents::Search(
40    const string16& in_this, size_t* match_index, size_t* match_length) {
41  UErrorCode status = U_ZERO_ERROR;
42  usearch_setText(search_, in_this.data(), in_this.size(), &status);
43
44  // Default to basic substring search if usearch fails. According to
45  // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
46  // if either |find_this| or |in_this| are empty. In either case basic
47  // substring search will give the correct return value.
48  if (!U_SUCCESS(status)) {
49    size_t index = in_this.find(find_this_);
50    if (index == string16::npos) {
51      return false;
52    } else {
53      if (match_index)
54        *match_index = index;
55      if (match_length)
56        *match_length = find_this_.size();
57      return true;
58    }
59  }
60
61  int32_t index = usearch_first(search_, &status);
62  if (!U_SUCCESS(status) || index == USEARCH_DONE)
63    return false;
64  if (match_index)
65    *match_index = static_cast<size_t>(index);
66  if (match_length)
67    *match_length = static_cast<size_t>(usearch_getMatchedLength(search_));
68  return true;
69}
70
71bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
72                                        const string16& in_this,
73                                        size_t* match_index,
74                                        size_t* match_length) {
75  return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search(
76      in_this, match_index, match_length);
77}
78
79}  // namespace i18n
80}  // namespace base
81