'How to replace a string using a wrapper function in Julia

I am trying to write a Julia function that performs a find and replace operation on each element in an array of strings using regular expressions. It is essentially a wrapper around a broadcasted replace() call. If you are familiar with R's stringr package, this function should more or less work the same as stringr::str_replace_all().

The code below replaces all instances of 'ee' with 'EE', replacing "greetings" with "grEEtings":

arr = ["hi", "hello", "welcome", "greetings"]
replace.(arr, r"e{2}" => "EE")

The function I wrote does not return modifications of the values in arr:

function str_replace_all(string::String, pattern::String, replacement::String)
    replace.(string, Regex(pattern) => replacement)
end

str_replace_all(arr, "e{2}", "EE")

What went wrong? Thanks!



Solution 1:[1]

The code you provided does not yet run, since you are trying to pass a String, but your function expects an Array of Strings. You either have to:

  1. Remove the type annotation of string::String in the function definition, or

  2. vectorize your function when calling it, using the '.' syntax: str_replace_all.(arr, "e{2}", "EE")

It should also be noted that your function will not replace strings in the array, it will create a new array containing the replaced values. If you want to get the replaced values in your array, you could do something like (Edit: as DNF noted in the comments, this way a new array is created and binded to the variable arr, which is not really efficient):

function str_replace_all(string, pattern::String, replacement::String)
    replace.(string, Regex(pattern) => replacement)
end

arr = str_replace_all(arr, "e{2}", "EE")

Solution 2:[2]

drop type annotations in your function and it should work:

julia> arr = ["hi", "hello", "welcome", "greetings"]

julia> function str_replace_all(string, pattern, replacement)
    replace.(string, Regex(pattern) => replacement)
end

Solution 3:[3]

You have to actually modify the array:

function str_replace_all!(arr, pattern, replacement)
    arr .= replace.(arr, pattern => replacement)
end

You should put a ! at the end of the function name to signal that it mutates the input. That is only a convention, it has no effect, but you should follow it nonetheless.

Solution 4:[4]

After incorporating feedback from everyone's answers, here is my solution:

function str_replace_all(string::String, pattern::String, replacement::String)
    replace(string, pattern => replacement)
end
function str_replace_all(string::String, pattern::Regex, replacement::String)
    replace(string, pattern => replacement)
end

It is best to take advantage of multiple dispatch to allow users to decide on the type of pattern to send to replace()--an exact match (string) or a regular expression. Further, vectorization of the solution should be done when calling the function (e.g. str_replace_all.()) instead of being placed inside the function's body (as was the case with the call to replace.() in the OP).

Ex:

arr = ["hi", "hello", "welcome", "greetings"]
str_replace_all.(arr, "ee", "EE")
str_replace_all.(arr, r"e{2}", "EE")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 ????????
Solution 3 DNF
Solution 4 Connor Krenzer