string_search.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. #include <stdint.h>
  5. #include "base/i18n/string_search.h"
  6. #include "base/check.h"
  7. #include "base/check_op.h"
  8. #include "third_party/icu/source/i18n/unicode/usearch.h"
  9. namespace base {
  10. namespace i18n {
  11. FixedPatternStringSearch::FixedPatternStringSearch(
  12. const std::u16string& find_this,
  13. bool case_sensitive)
  14. : find_this_(find_this) {
  15. // usearch_open requires a valid string argument to be searched, even if we
  16. // want to set it by usearch_setText afterwards. So, supplying a dummy text.
  17. const std::u16string& dummy = find_this_;
  18. UErrorCode status = U_ZERO_ERROR;
  19. search_ = usearch_open(find_this_.data(), find_this_.size(), dummy.data(),
  20. dummy.size(), uloc_getDefault(),
  21. nullptr, // breakiter
  22. &status);
  23. if (U_SUCCESS(status)) {
  24. // http://icu-project.org/apiref/icu4c40/ucol_8h.html#6a967f36248b0a1bc7654f538ee8ba96
  25. // Set comparison level to UCOL_PRIMARY to ignore secondary and tertiary
  26. // differences. Set comparison level to UCOL_TERTIARY to include all
  27. // comparison differences.
  28. // Diacritical differences on the same base letter represent a
  29. // secondary difference.
  30. // Uppercase and lowercase versions of the same character represents a
  31. // tertiary difference.
  32. UCollator* collator = usearch_getCollator(search_);
  33. ucol_setStrength(collator, case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY);
  34. usearch_reset(search_);
  35. }
  36. }
  37. FixedPatternStringSearch::~FixedPatternStringSearch() {
  38. if (search_)
  39. usearch_close(search_);
  40. }
  41. bool FixedPatternStringSearch::Search(const std::u16string& in_this,
  42. size_t* match_index,
  43. size_t* match_length,
  44. bool forward_search) {
  45. UErrorCode status = U_ZERO_ERROR;
  46. usearch_setText(search_, in_this.data(), in_this.size(), &status);
  47. // Default to basic substring search if usearch fails. According to
  48. // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
  49. // if either |find_this| or |in_this| are empty. In either case basic
  50. // substring search will give the correct return value.
  51. if (!U_SUCCESS(status)) {
  52. size_t index = in_this.find(find_this_);
  53. if (index == std::u16string::npos)
  54. return false;
  55. if (match_index)
  56. *match_index = index;
  57. if (match_length)
  58. *match_length = find_this_.size();
  59. return true;
  60. }
  61. int32_t index = forward_search ? usearch_first(search_, &status)
  62. : usearch_last(search_, &status);
  63. if (!U_SUCCESS(status) || index == USEARCH_DONE)
  64. return false;
  65. if (match_index)
  66. *match_index = static_cast<size_t>(index);
  67. if (match_length)
  68. *match_length = static_cast<size_t>(usearch_getMatchedLength(search_));
  69. return true;
  70. }
  71. FixedPatternStringSearchIgnoringCaseAndAccents::
  72. FixedPatternStringSearchIgnoringCaseAndAccents(
  73. const std::u16string& find_this)
  74. : base_search_(find_this, /*case_sensitive=*/false) {}
  75. bool FixedPatternStringSearchIgnoringCaseAndAccents::Search(
  76. const std::u16string& in_this,
  77. size_t* match_index,
  78. size_t* match_length) {
  79. return base_search_.Search(in_this, match_index, match_length,
  80. /*forward_search=*/true);
  81. }
  82. bool StringSearchIgnoringCaseAndAccents(const std::u16string& find_this,
  83. const std::u16string& in_this,
  84. size_t* match_index,
  85. size_t* match_length) {
  86. return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search(
  87. in_this, match_index, match_length);
  88. }
  89. bool StringSearch(const std::u16string& find_this,
  90. const std::u16string& in_this,
  91. size_t* match_index,
  92. size_t* match_length,
  93. bool case_sensitive,
  94. bool forward_search) {
  95. return FixedPatternStringSearch(find_this, case_sensitive)
  96. .Search(in_this, match_index, match_length, forward_search);
  97. }
  98. RepeatingStringSearch::RepeatingStringSearch(const std::u16string& find_this,
  99. const std::u16string& in_this,
  100. bool case_sensitive)
  101. : find_this_(find_this), in_this_(in_this) {
  102. std::string locale = uloc_getDefault();
  103. UErrorCode status = U_ZERO_ERROR;
  104. search_ = usearch_open(find_this_.data(), find_this_.size(), in_this_.data(),
  105. in_this_.size(), locale.data(), /*breakiter=*/nullptr,
  106. &status);
  107. DCHECK(U_SUCCESS(status));
  108. if (U_SUCCESS(status)) {
  109. // http://icu-project.org/apiref/icu4c40/ucol_8h.html#6a967f36248b0a1bc7654f538ee8ba96
  110. // Set comparison level to UCOL_PRIMARY to ignore secondary and tertiary
  111. // differences. Set comparison level to UCOL_TERTIARY to include all
  112. // comparison differences.
  113. // Diacritical differences on the same base letter represent a
  114. // secondary difference.
  115. // Uppercase and lowercase versions of the same character represents a
  116. // tertiary difference.
  117. UCollator* collator = usearch_getCollator(search_);
  118. ucol_setStrength(collator, case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY);
  119. usearch_reset(search_);
  120. }
  121. }
  122. RepeatingStringSearch::~RepeatingStringSearch() {
  123. if (search_)
  124. usearch_close(search_);
  125. }
  126. bool RepeatingStringSearch::NextMatchResult(int& match_index,
  127. int& match_length) {
  128. UErrorCode status = U_ZERO_ERROR;
  129. const int match_start = usearch_next(search_, &status);
  130. if (U_FAILURE(status) || match_start == USEARCH_DONE)
  131. return false;
  132. DCHECK(U_SUCCESS(status));
  133. match_index = match_start;
  134. match_length = usearch_getMatchedLength(search_);
  135. return true;
  136. }
  137. } // namespace i18n
  138. } // namespace base