| 87 | } |
| 88 | |
| 89 | Value ExtractAll(int regex_max_program_size, const StringValue& target, |
| 90 | const StringValue& regex, |
| 91 | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
| 92 | google::protobuf::MessageFactory* absl_nonnull message_factory, |
| 93 | google::protobuf::Arena* absl_nonnull arena) { |
| 94 | std::string target_scratch; |
| 95 | std::string regex_scratch; |
| 96 | absl::string_view target_view = target.ToStringView(&target_scratch); |
| 97 | absl::string_view regex_view = regex.ToStringView(®ex_scratch); |
| 98 | RE2 re2(regex_view, cel::internal::MakeRE2Options()); |
| 99 | CEL_RETURN_IF_ERROR(cel::internal::CheckRE2(re2, regex_max_program_size)) |
| 100 | .With(ErrorValueReturn()); |
| 101 | const int group_count = re2.NumberOfCapturingGroups(); |
| 102 | if (group_count > 1) { |
| 103 | return ErrorValue(absl::InvalidArgumentError(absl::StrFormat( |
| 104 | "regular expression has more than one capturing group: %s", |
| 105 | regex_view))); |
| 106 | } |
| 107 | |
| 108 | auto builder = NewListValueBuilder(arena); |
| 109 | absl::string_view temp_target = target_view; |
| 110 | |
| 111 | // Space for the full match (\0) and the first capture group (\1). |
| 112 | absl::string_view submatches[2]; |
| 113 | const int group_to_extract = (group_count == 1) ? 1 : 0; |
| 114 | |
| 115 | while (re2.Match(temp_target, 0, temp_target.length(), RE2::UNANCHORED, |
| 116 | submatches, group_count + 1)) { |
| 117 | const absl::string_view& full_match = submatches[0]; |
| 118 | const absl::string_view& desired_capture = submatches[group_to_extract]; |
| 119 | |
| 120 | // Avoid infinite loops on zero-length matches |
| 121 | if (full_match.empty()) { |
| 122 | if (temp_target.empty()) { |
| 123 | break; |
| 124 | } |
| 125 | temp_target.remove_prefix(1); |
| 126 | continue; |
| 127 | } |
| 128 | |
| 129 | if (group_count == 1 && desired_capture.empty()) { |
| 130 | temp_target.remove_prefix(full_match.data() - temp_target.data() + |
| 131 | full_match.length()); |
| 132 | continue; |
| 133 | } |
| 134 | |
| 135 | absl::Status status = |
| 136 | builder->Add(StringValue::From(desired_capture, arena)); |
| 137 | if (!status.ok()) { |
| 138 | return ErrorValue(status); |
| 139 | } |
| 140 | temp_target.remove_prefix(full_match.data() - temp_target.data() + |
| 141 | full_match.length()); |
| 142 | } |
| 143 | |
| 144 | return std::move(*builder).Build(); |
| 145 | } |
| 146 |
nothing calls this directly
no test coverage detected