Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cpp/src/arrow/compute/kernels/scalar_string_ascii.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,10 @@ struct PlainSubstringReplacer {

static Result<std::unique_ptr<PlainSubstringReplacer>> Make(
const ReplaceSubstringOptions& options, bool is_utf8) {
if (options.pattern.empty()) {
// An empty pattern would match at every position without advancing.
return Status::Invalid("Empty substring pattern is not supported");
}
return std::make_unique<PlainSubstringReplacer>(options);
}

Expand Down Expand Up @@ -2119,7 +2123,8 @@ struct RegexSubstringReplacer {
re2::StringPiece replacement(options_.replacement);

// If s is empty, then it's essentially global
if (options_.max_replacements == -1 || s.empty()) {
// Any negative value means unlimited replacements.
if (options_.max_replacements < 0 || s.empty()) {
std::string s_copy{s.data(), s.length()};
RE2::GlobalReplace(&s_copy, regex_replacement_, replacement);
return builder->Append(reinterpret_cast<const uint8_t*>(s_copy.data()),
Expand Down
12 changes: 12 additions & 0 deletions cpp/src/arrow/compute/kernels/scalar_string_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2102,6 +2102,13 @@ TYPED_TEST(TestBaseBinaryKernels, ReplaceSubstring) {

Datum input = ArrayFromJSON(this->type(), "[]");
ASSERT_RAISES(Invalid, CallFunction("replace_substring", {input}));

// GH-39149: an empty pattern used to loop forever
input = ArrayFromJSON(this->type(), R"(["abc", "", null])");
for (int64_t max_replacements : {-1, -3, 1}) {
options = ReplaceSubstringOptions{"", "x", max_replacements};
ASSERT_RAISES(Invalid, CallFunction("replace_substring", {input}, &options));
}
}

#ifdef ARROW_WITH_RE2
Expand All @@ -2120,6 +2127,11 @@ TYPED_TEST(TestBaseBinaryKernels, ReplaceSubstringRegex) {
this->CheckUnary("replace_substring_regex", R"([""])", this->type(), R"(["x"])",
&options);

// GH-39149: negative max_replacements other than -1 means unlimited
options = ReplaceSubstringOptions{"", "x", -3};
this->CheckUnary("replace_substring_regex", R"(["abc"])", this->type(),
R"(["xaxbxcx"])", &options);

// ARROW-12774
options = ReplaceSubstringOptions{"X", "Y"};
this->CheckUnary("replace_substring_regex",
Expand Down
Loading