diff --git a/base/pcre.jl b/base/pcre.jl index e52bea2869eb7..a8edaaa089c31 100644 --- a/base/pcre.jl +++ b/base/pcre.jl @@ -228,7 +228,10 @@ function substring_length_bynumber(match_data, number) s = RefValue{Csize_t}() rc = ccall((:pcre2_substring_length_bynumber_8, PCRE_LIB), Cint, (Ptr{Cvoid}, Cint, Ref{Csize_t}), match_data, number, s) - rc < 0 && error("PCRE error: $(err_message(rc))") + if rc < 0 + rc == ERROR_UNSET && return 0 + error("PCRE error: $(err_message(rc))") + end return Int(s[]) end diff --git a/base/regex.jl b/base/regex.jl index a79f51995fab3..7fae9326c231b 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -528,6 +528,8 @@ replace_err(repl) = error("Bad replacement string: $repl") function _write_capture(io, re::RegexAndMatchData, group) len = PCRE.substring_length_bynumber(re.match_data, group) + # in the case of an optional group that doesn't match, len == 0 + len == 0 && return ensureroom(io, len+1) PCRE.substring_copy_bynumber(re.match_data, group, pointer(io.data, io.ptr), len+1) diff --git a/test/strings/util.jl b/test/strings/util.jl index 2ca6df529ba51..e8ea3b643fcda 100644 --- a/test/strings/util.jl +++ b/test/strings/util.jl @@ -275,6 +275,11 @@ end # Issue 13332 @test replace("abc", 'b' => 2.1) == "a2.1c" + # Issue 31456 + @test replace("The fox.", r"fox(es)?" => s"bus\1") == "The bus." + @test replace("The foxes.", r"fox(es)?" => s"bus\1") == "The buses." + @test replace("The quick fox quickly.", r"(quick)?\sfox(es)?\s(run)?" => s"\1 bus\2 \3") == "The quick bus quickly." + # test replace with a count for String and GenericString # check that replace is a no-op if count==0 for s in ["aaa", Test.GenericString("aaa")]