regex_set_matcher.cc 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright 2013 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 "components/url_matcher/regex_set_matcher.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/logging.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/substring_set_matcher/substring_set_matcher.h"
  11. #include "third_party/re2/src/re2/filtered_re2.h"
  12. #include "third_party/re2/src/re2/re2.h"
  13. using base::MatcherStringPattern;
  14. namespace url_matcher {
  15. RegexSetMatcher::RegexSetMatcher() = default;
  16. RegexSetMatcher::~RegexSetMatcher() = default;
  17. void RegexSetMatcher::AddPatterns(
  18. const std::vector<const MatcherStringPattern*>& regex_list) {
  19. if (regex_list.empty())
  20. return;
  21. for (size_t i = 0; i < regex_list.size(); ++i) {
  22. regexes_[regex_list[i]->id()] = regex_list[i];
  23. }
  24. RebuildMatcher();
  25. }
  26. void RegexSetMatcher::ClearPatterns() {
  27. regexes_.clear();
  28. RebuildMatcher();
  29. }
  30. bool RegexSetMatcher::Match(const std::string& text,
  31. std::set<MatcherStringPattern::ID>* matches) const {
  32. size_t old_number_of_matches = matches->size();
  33. if (regexes_.empty())
  34. return false;
  35. if (!filtered_re2_) {
  36. LOG(ERROR) << "RegexSetMatcher was not initialized";
  37. return false;
  38. }
  39. // FilteredRE2 expects lowercase for prefiltering, but we still
  40. // match case-sensitively.
  41. std::vector<RE2ID> atoms(FindSubstringMatches(base::ToLowerASCII(text)));
  42. std::vector<RE2ID> re2_ids;
  43. filtered_re2_->AllMatches(text, atoms, &re2_ids);
  44. for (size_t i = 0; i < re2_ids.size(); ++i) {
  45. MatcherStringPattern::ID id = re2_id_map_[re2_ids[i]];
  46. matches->insert(id);
  47. }
  48. return old_number_of_matches != matches->size();
  49. }
  50. bool RegexSetMatcher::IsEmpty() const {
  51. return regexes_.empty();
  52. }
  53. std::vector<RegexSetMatcher::RE2ID> RegexSetMatcher::FindSubstringMatches(
  54. const std::string& text) const {
  55. std::set<base::MatcherStringPattern::ID> atoms_set;
  56. substring_matcher_->Match(text, &atoms_set);
  57. return std::vector<RE2ID>(atoms_set.begin(), atoms_set.end());
  58. }
  59. void RegexSetMatcher::RebuildMatcher() {
  60. re2_id_map_.clear();
  61. filtered_re2_ = std::make_unique<re2::FilteredRE2>();
  62. if (regexes_.empty())
  63. return;
  64. for (auto it = regexes_.begin(); it != regexes_.end(); ++it) {
  65. RE2ID re2_id;
  66. RE2::ErrorCode error =
  67. filtered_re2_->Add(it->second->pattern(), RE2::DefaultOptions, &re2_id);
  68. if (error == RE2::NoError) {
  69. DCHECK_EQ(static_cast<RE2ID>(re2_id_map_.size()), re2_id);
  70. re2_id_map_.push_back(it->first);
  71. } else {
  72. // Unparseable regexes should have been rejected already in
  73. // URLMatcherFactory::CreateURLMatchesCondition.
  74. LOG(ERROR) << "Could not parse regex (id=" << it->first << ", "
  75. << it->second->pattern() << ")";
  76. }
  77. }
  78. std::vector<std::string> strings_to_match;
  79. filtered_re2_->Compile(&strings_to_match);
  80. std::vector<MatcherStringPattern> substring_patterns;
  81. substring_patterns.reserve(strings_to_match.size());
  82. // Build SubstringSetMatcher from |strings_to_match|.
  83. for (size_t i = 0; i < strings_to_match.size(); ++i)
  84. substring_patterns.emplace_back(std::move(strings_to_match[i]), i);
  85. substring_matcher_ = std::make_unique<base::SubstringSetMatcher>();
  86. bool success = substring_matcher_->Build(substring_patterns);
  87. CHECK(success);
  88. }
  89. } // namespace url_matcher