diff --git a/R/replace.R b/R/replace.R index 059e31c6..ae5c31ee 100644 --- a/R/replace.R +++ b/R/replace.R @@ -223,13 +223,14 @@ str_transform_all <- function( replacement, error_call = caller_env() ) { + nms <- names(string) locs <- str_locate_all(string, pattern) old <- str_sub_all(string, locs) # unchop list into a vector, apply replacement(), and then rechop back into # a list - old_flat <- vctrs::list_unchop(old) + old_flat <- vctrs::list_unchop(unname(old)) if (length(old_flat) == 0) { # minor optimisation to avoid problems with the many replacement # functions that use paste @@ -271,6 +272,7 @@ str_transform_all <- function( new <- vctrs::vec_chop(new_flat, idx) stringi::stri_sub_all(string, locs) <- new + names(string) <- nms string } diff --git a/tests/testthat/test-replace.R b/tests/testthat/test-replace.R index 2ee1a317..2010318e 100644 --- a/tests/testthat/test-replace.R +++ b/tests/testthat/test-replace.R @@ -153,6 +153,17 @@ test_that("replace functions preserve names", { expect_equal(names(str_replace_all(x, "[0-9]", "x")), names(x)) }) +test_that("str_replace_all works with named input and function replacement (#595)", { + expect_equal( + str_replace_all(c(name = "string string"), "string", function(x) rep("strong", length(x))), + c(name = "strong strong") + ) + expect_equal( + str_replace_all(c(a = "a1 b2", b = "c3"), "[a-z]", toupper), + c(a = "A1 B2", b = "C3") + ) +}) + test_that("replace functions handle vectorised patterns and names", { x1 <- c(A = "ab") p2 <- c("a", "b")