# How to replace the charactors in the string?

**URL:** <https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 6, 2019, 5:35am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778 "2019-11-06T05:35:08Z")\
**Posts on this page:** 15\
**Page:** 2

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 5:32am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/21 "2019-11-07T05:32:28Z")

</div>

if don’t println, it costs 0.173 seconds

---

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 5:43am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/22 "2019-11-07T05:43:13Z")

</div>

if ‘o’=\>‘a’ and ‘a’=\>‘o’, does it work? because Perl tr can do it.

tr/ao/oa/

‘The cat sat on the mat’  
to  
‘The cot sot an the mot’

Every character changes ( ‘a’ to ‘o’ and ‘o’ to ‘a’) independently against the original string.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [November 7, 2019, 5:55am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/24 "2019-11-07T05:55:26Z")

</div>

No, in its current form it applies both replacements sequentially (as you can see above). Clearly, a simple loop would give you what you want. But I feel there really should just be a proper multi-pair version `replace("hallo", 'a'=>'o', 'o'=>'a')`.

UPDATE: Oh, apparently I wanted this before as I gave [https://github.com/JuliaLang/julia/pull/30457](https://github.com/JuliaLang/julia/pull/30457) a heart 🙂

---

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 6:00am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/25 "2019-11-07T06:00:46Z")

</div>

If that, can simplify the syntax like the above [jling](https://discourse.julialang.org/u/jling)’s function?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [November 7, 2019, 6:11am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/26 "2019-11-07T06:11:25Z")

</div>

> [@carstenbauer](#):
>
> replace(“hallo”, ‘a’=\>‘o’, ‘o’=\>‘a’)

@Yan just try this yourself please, that’s why I have to split and join a string as an array of chars.

---

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 6:26am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/27 "2019-11-07T06:26:11Z")

</div>

> [@jling](#):
>
> replace(“hallo”, ‘a’=\>‘o’, ‘o’=\>‘a’)

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/3/138157b793e7ed5cd5a39c3bf95b95f4a95881ed.png)  
I mean the syntax is good like tr(mystring, “ao”, “oa”)

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [November 7, 2019, 8:55am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/28 "2019-11-07T08:55:43Z")

</div>

See also this discussion: [How to replace several characters in a string using Julia - Stack Overflow](https://stackoverflow.com/questions/35782439/how-to-replace-several-characters-in-a-string-using-julia)

This appears to be fast:

```julia
function tr(str, reps...)
    d = Dict(reps)
    return(map(s -> get(d,s,s), str))
end

julia> mystring = "The cat sat on the mat"
"The cat sat on the mat"

julia> @btime perl_tr(mystring,"ao","oL")
  1.406 μs (21 allocations: 1.45 KiB)
"The cot sot Ln the mot"

julia> @btime tr(mystring,'a'=>'o','o'=>'L')
  951.000 ns (10 allocations: 768 bytes)
"The cot sot Ln the mot"

```

(as long as you only replace single characters defined with: `'c'` (and not strings with `"str"`)

---

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 11:59am UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/29 "2019-11-07T11:59:47Z")

</div>

Good, the performance is improved.  
It still costs 0.139851 and 0.091713 seconds for 100000 loops, but Perl costs only 0.015 seconds.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [November 7, 2019, 1:12pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/30 "2019-11-07T13:12:28Z")

</div>

Use `@btime` from BenchmarkTools.jl for benchmarking instead of `@time`. (See [my post above](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/20).)

---

<div class="post-metadata">

**Author:** ![Yan](https://avatars.discourse-cdn.com/v4/letter/y/3e96dc/32.png) [@Yan](https://discourse.julialang.org/u/Yan)\
**Post date:** [November 7, 2019, 1:27pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/31 "2019-11-07T13:27:11Z")

</div>

Oh, only 13 ns using @btime test, but it seems unbelievable.

I test 1000000 loops again. Perl is obvious faster although it is 0.18 s using Perl times test

I am wondering if the @btime is not support “@btime begin… end”.

and I think the @time test is quite similar to the Perl times test.

Don’t worry about screen scrolling, I run them by using " julia new\_trans.jl \> temp.julia.txt"

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 7, 2019, 3:24pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/33 "2019-11-07T15:24:37Z")

</div>

> [@laborg](#):
>
> This appears to be fast:

If you are going to apply this replacement to many small strings (which is the only situation in which you actually care about the performance on small strings), then you would want to cache the dictionary between calls. That saves me 30% on my machine. I save an additional 20% by using an explicit loop and no dictionary.

```julia
julia> @btime tr($mystring,$('a'=>'o'),$('o'=>'L'))
  925.393 ns (9 allocations: 736 bytes)
"The cot sot Ln the mot"

julia> d = Dict('a'=>'o','o'=>'L')
Dict{Char,Char} with 2 entries:
  'a' => 'o'
  'o' => 'L'

julia> tr(str, d::Dict) = map(s -> get(d,s,s), str)
tr (generic function with 2 methods)

julia> @btime tr($mystring,$d)
  654.245 ns (5 allocations: 256 bytes)
"The cot sot Ln the mot"

julia> function mytr(s)
           buf = IOBuffer(sizehint=sizeof(s))
           for c in s
               print(buf, c == 'a' ? 'o' : c == 'o' ? 'L' : c)
           end
           return String(take!(buf))
       end
mytr (generic function with 1 method)

julia> @btime mytr($mystring)
  451.426 ns (4 allocations: 240 bytes)
"The cot sot Ln the mot"

```

You can probably make things even faster if you take advantage of the fact that your replacements are ASCII, in which case you can look at individual bytes rather than decoding/comparing Unicode characters. But that might be excessive work for such a simple function. (Heck, you could go even further by grabbing multi-byte chunks and using SIMD instructions.)

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [November 7, 2019, 3:30pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/34 "2019-11-07T15:30:41Z")

</div>

Yes good idea, but the bottleneck `Dict` remains in a generic usage. Instead of using Dict I tried out unrolling the replacement with the package `Unrolled`, and voila:

```julia
julia> using Unrolled

julia> @unroll function decider(c,reps)
           @unroll for x in reps
               if x.first == c return x.second end
           end
           return c
       end
decider_unrolled_expansion_ (generic function with 1 method)

julia> tr(str, reps...) = map(s -> decider(s,reps), str)
tr (generic function with 1 method)

julia> @btime tr("The cat sat on the mat",'a'=>'o','o'=>'L')
  271.617 ns (4 allocations: 240 bytes)
"The cot sot Ln the mot"

```

The speed is no getting towards Perl. I’m not sure if the Perl version allocates memory in each iteration…

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 7, 2019, 6:59pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/35 "2019-11-07T18:59:08Z")

</div>

> [@laborg](#):
>
> The speed is now getting towards Perl. I’m not sure if the Perl version allocates memory in each iteration…

Perl uses reference counting for memory management, and it is probably more efficient for allocating and then discarding many small strings like you are doing here. (Indeed, working with lots of small strings is probably the main situation that Perl’s memory management is optimized for.) (Julia uses [mark-and-sweep](https://discourse.julialang.org/t/details-about-julias-garbage-collector-reference-counting/18021) garbage collection, because reference counting imposes other tradeoffs for compiled and multithreaded code.)

The real question here: in what circumstance is the `tr` operation on small strings performance-critical? In a given realistic setting, there is usually a way to avoid doing lots of re-allocations in your inner loop…

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [November 7, 2019, 7:27pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/36 "2019-11-07T19:27:20Z")

</div>

Well, if anything, allocating a lot of temporary object is what tracing GC is good for… Obviously you can add optimization to reference counting to deal with this but the most naive form will get hurt a lot by repeated ref count operation and repeated freeing.

---

<div class="post-metadata">

**Author:** ![tkluck](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkluck/32/15769_2.png) [@tkluck](https://discourse.julialang.org/u/tkluck)\
**Post date:** [November 7, 2019, 9:24pm UTC](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778/37 "2019-11-07T21:24:18Z")

</div>

> [@stevengj](#):
>
> Perl uses reference counting for memory management, and it is probably more efficient for allocating and then discarding many small strings like you are doing here.

Possibly more importantly, perl’s strings are mutable, so a `tr` operation can happen in-place.

[Previous page](https://discourse.julialang.org/t/how-to-replace-the-charactors-in-the-string/30778.md?page=1)
