# Left and right division for strings

**URL:** https://discourse.julialang.org/t/left-and-right-division-for-strings/109839
**Category:** Internals & Design
**Tags:** strings, arithmetic
**Created:** [February 6, 2024, 9:31pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839 "2024-02-06T21:31:04Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [February 6, 2024, 9:31pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/1 "2024-02-06T21:31:04Z")

</div>

For numbers and matrices, we have `x * y / y == x` and `x \ (x * y) == y`. Since we have `*` for strings, we could implement `/` and `\` for strings too:

```julia
"abcd" / "cd" == "ab"
"ab" \ "abcd" == "cd"

```

AFAICT, it would be algebraically sound, useful, and fun. What do you think?

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [February 6, 2024, 9:37pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/2 "2024-02-06T21:37:05Z")

</div>

Very fun. What should the behaviour be if one does `"ab" \ "cd"`? The only reasonable thing seems to be to throw and error, which makes me wonder how much utility this’d really have.

That said, if we also supported division by a `Regex`, that’d actually make this thing quite a cute and occasionally useful pattern

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [February 6, 2024, 9:39pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/3 "2024-02-06T21:39:24Z")

</div>

Well, it’s more like integer division though, i.e., you won’t have

```julia
("abc" * "de") / "cde" == "abc" * ("de" / "cde")

```

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [February 6, 2024, 9:39pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/4 "2024-02-06T21:39:29Z")

</div>

In what situation would this be used?

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [February 6, 2024, 9:41pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/5 "2024-02-06T21:41:55Z")

</div>

Python has `str.removeprefix` and `str.removesuffix` which are similar.

```julia
Signature: str.removeprefix(self, prefix, /)
Docstring:
Return a str with the given prefix string removed if present.

If the string starts with the prefix string, return string[len(prefix):].
Otherwise, return a copy of the original string.

```

```julia
Signature: str.removesuffix(self, suffix, /)
Docstring:
Return a str with the given suffix string removed if present.

If the string ends with the suffix string and that suffix is not empty,
return string[:-len(suffix)]. Otherwise, return a copy of the original
string.

```

Haskell has [`stripPrefix` and `stripSuffix`](https://hackage.haskell.org/package/fay-base-0.21.2.0/docs/Data-List.html) for `List` (and String is a List of Char in Haskell).

---

<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: [February 6, 2024, 9:44pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/6 "2024-02-06T21:44:40Z")

</div>

> [@jar1](#):
>
> Python has `str.removeprefix` and `str.removesuffix` which are similar.

Except that these don’t throw an error if the prefix/suffix aren’t present. ~~A more natural analogue in Julia might be to add more optional arguments to [`chop`](https://docs.julialang.org/en/v1/base/strings/#Base.chop), e.g. `chop(s, prefix="foo", suffix="bar")`.~~ Julia already has the functions [`chopprefix`](https://docs.julialang.org/en/v1/base/strings/#Base.chopprefix) and [`chopsuffix`](https://docs.julialang.org/en/v1/base/strings/#Base.chopsuffix) for this.

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [February 6, 2024, 9:45pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/7 "2024-02-06T21:45:56Z")

</div>

I don’t work with strings much, but I have found myself in a few situations before where I’ve done things like

```julia
if endswith(path, ".jl")
    path[begin:end-3]
end

```

could instead be

```julia
if endswith(path, ".jl")
    path / ".jl"
end

```

That’s a really simple example, but I’ve found a few times when writing string macros, that there’s often prefixes or suffixes I know are there that I want to chop off.

---

<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: [February 6, 2024, 9:47pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/8 "2024-02-06T21:47:01Z")

</div>

> [@Mason](#):
>
> ```julia
> if endswith(path, ".jl")
> s / ".jl"
> end
> 
> ```

`chopsuffix(s, ".jl")` was added in Julia 1.8.

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [February 6, 2024, 9:47pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/9 "2024-02-06T21:47:30Z")

</div>

> [@stevengj](#):
>
> `chopsuffix(s, ".jl")` was added in Julia 1.8.

Sure, but where’s the fun in that?

---

<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: [February 6, 2024, 9:48pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/10 "2024-02-06T21:48:11Z")

</div>

> [@Mason](#):
>
> `s[begin:end-3]`

Note also that this is buggy:

```julia
julia> s = "α.jl"
"α.jl"

julia> s[begin:end-3]
ERROR: StringIndexError: invalid index [2], valid nearby indices [1]=>'α', [3]=>'.'

```

(It’s really tempting to write this, which is a key motivation for a [`StringIndex` type](https://discourse.julialang.org/t/stringindex-idea-julia-2-0/107185).)

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [February 6, 2024, 9:52pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/11 "2024-02-06T21:52:13Z")

</div>

> [@stevengj](#):
>
> (It’s really tempting to write this, which is a key motivation for a [`StringIndex` type](https://discourse.julialang.org/t/stringindex-idea-julia-2-0/107185).)

Nice try, but I will _not_ be tempted into that tar-pit of a thread today 😅

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [February 6, 2024, 9:55pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/12 "2024-02-06T21:55:22Z")

</div>

Like the idea about regex and just checked that regular languages are closed under union, intersection, complement and concatenation. Thus one could indeed define difference as

```julia
\(ra::Regex, rb::Regex) = !rb ∩ ra

```

with `!` and `∩` being complement and intersection respectively. Not sure if this efficient in general though?  
Interestingly, `\` is not defined on sets as difference either – the fallback method is applicable, but fails.

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [February 6, 2024, 10:00pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/13 "2024-02-06T22:00:59Z")

</div>

Even though regular languages are closed under complementation, unfortunately I don’t think PCRE supports complement. [How do I turn any regex into an complement of itself without complex hand editing? - Stack Overflow](https://stackoverflow.com/a/3979997)

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [February 6, 2024, 10:16pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/14 "2024-02-06T22:16:16Z")

</div>

Was proposed and declined in Julia#13411. There’s also the consideration that `/` could alternatively represent path concatenation (also declined in Julia#9488).

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [February 6, 2024, 10:29pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/15 "2024-02-06T22:29:17Z")

</div>

> [@mbauman](#):
>
> `/` could alternatively represent path concatenation (also declined in [Julia#9488](https://github.com/JuliaLang/julia/issues/9488)).

I don’t like `Base./` for path concat, since it has nothing to do with division.

@StefanKarpinski said in [string division: "pre"\"prefix" =\> "fix", "suffix"/"fix" =\> "suf". by StefanKarpinski · Pull Request #13411 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/13411)

> We should either stop using `*` for string concatenation or we should “double down”.

I agree with that. [`append`/`concat` function · Issue #53040 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/53040) proposes an alternative concatenation function `append`.

> [@bertschi](#):
>
> Well, it’s more like integer division though, i.e., you won’t have
> 
> ```julia
> ("abc" * "de") / "cde" == "abc" * ("de" / "cde")
> 
> ```

What do you expect `"de" / "cde"` to do here?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [February 6, 2024, 10:54pm UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/16 "2024-02-06T22:54:46Z")

</div>

> [@jar1](#):
>
> What do you expect `"de" / "cde"` to do here?

Good question, by analogy with integer division it should be `zero`, i.e., an absorbing element for `*`.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [February 7, 2024, 12:20am UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/17 "2024-02-07T00:20:54Z")

</div>

Just for fun:

```julia
import Base: /, \
/(x::String, y::String) = begin s = replace(x, y => "", count=1); s == x ? "" : s; end
\(x::String, y::String) = /(y::String, x::String) 

"abcd" / "cd" # == "ab"
"ab" \ "abcd" # == "cd" 
"de" / "cde" # == ""

```

---

<div class="post-metadata">

### Author: ![mleseach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mleseach/32/202840_2.png) [@mleseach](https://discourse.julialang.org/u/mleseach)
#### Post date: [February 7, 2024, 2:02am UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/18 "2024-02-07T02:02:45Z")

</div>

Obviously it should be `"abd⁻¹c⁻¹"`

---

<div class="post-metadata">

### Author: ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)
#### Post date: [February 7, 2024, 2:26am UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/19 "2024-02-07T02:26:14Z")

</div>

> [@mleseach](#):
>
> Obviously it should be `"abd⁻¹c⁻¹"`

Or a `Rational{String}` typed `"ab"//"cd"` 😜

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [February 7, 2024, 10:15am UTC](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839/20 "2024-02-07T10:15:15Z")

</div>

> [@Mason](#):
>
> ```julia
> if endswith(path, ".jl")
> path[begin:end-3]
> end
> 
> ```

I’d use [`splitext`](https://docs.julialang.org/en/v1/base/file/#Base.Filesystem.splitext) for this.

[Next page](https://discourse.julialang.org/t/left-and-right-division-for-strings/109839.md?page=2)
