| 172 | } |
| 173 | |
| 174 | Value ReplaceN(int regex_max_program_size, const StringValue& target, |
| 175 | const StringValue& regex, const StringValue& replacement, |
| 176 | int64_t count, |
| 177 | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
| 178 | google::protobuf::MessageFactory* absl_nonnull message_factory, |
| 179 | google::protobuf::Arena* absl_nonnull arena) { |
| 180 | if (count == 0) { |
| 181 | return target; |
| 182 | } |
| 183 | if (count < 0) { |
| 184 | return ReplaceAll(regex_max_program_size, target, regex, replacement, |
| 185 | descriptor_pool, message_factory, arena); |
| 186 | } |
| 187 | |
| 188 | std::string target_scratch; |
| 189 | std::string regex_scratch; |
| 190 | std::string replacement_scratch; |
| 191 | absl::string_view target_view = target.ToStringView(&target_scratch); |
| 192 | absl::string_view regex_view = regex.ToStringView(®ex_scratch); |
| 193 | absl::string_view replacement_view = |
| 194 | replacement.ToStringView(&replacement_scratch); |
| 195 | RE2 re2(regex_view, cel::internal::MakeRE2Options()); |
| 196 | CEL_RETURN_IF_ERROR(cel::internal::CheckRE2(re2, regex_max_program_size)) |
| 197 | .With(ErrorValueReturn()); |
| 198 | std::string error_string; |
| 199 | if (!re2.CheckRewriteString(replacement_view, &error_string)) { |
| 200 | return ErrorValue(absl::InvalidArgumentError( |
| 201 | absl::StrFormat("invalid replacement string: %s", error_string))); |
| 202 | } |
| 203 | |
| 204 | std::string output; |
| 205 | absl::string_view temp_target = target_view; |
| 206 | int replaced_count = 0; |
| 207 | // RE2's Rewrite only supports substitutions for groups \0 through \9. |
| 208 | absl::string_view match[10]; |
| 209 | int nmatch = std::min(9, re2.NumberOfCapturingGroups()) + 1; |
| 210 | |
| 211 | while (replaced_count < count && |
| 212 | re2.Match(temp_target, 0, temp_target.length(), RE2::UNANCHORED, match, |
| 213 | nmatch)) { |
| 214 | absl::string_view full_match = match[0]; |
| 215 | |
| 216 | output.append(temp_target.data(), full_match.data() - temp_target.data()); |
| 217 | |
| 218 | if (!re2.Rewrite(&output, replacement_view, match, nmatch)) { |
| 219 | // This should ideally not happen given CheckRewriteString passed |
| 220 | return ErrorValue(absl::InternalError("rewrite failed unexpectedly")); |
| 221 | } |
| 222 | |
| 223 | temp_target.remove_prefix(full_match.data() - temp_target.data() + |
| 224 | full_match.length()); |
| 225 | replaced_count++; |
| 226 | } |
| 227 | |
| 228 | output.append(temp_target.data(), temp_target.length()); |
| 229 | |
| 230 | return StringValue::From(std::move(output), arena); |
| 231 | } |
nothing calls this directly
no test coverage detected