# Create string out of substring in dataframe

**URL:** https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206
**Category:** General Usage
**Tags:** dataframes
**Created:** [September 25, 2023, 1:15am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206 "2023-09-25T01:15:01Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![jonjilla](https://avatars.discourse-cdn.com/v4/letter/j/7ba0ec/32.png) [@jonjilla](https://discourse.julialang.org/u/jonjilla)
#### Post date: [September 25, 2023, 1:15am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/1 "2023-09-25T01:15:01Z")

</div>

I’m trying to create a new string parsed out of a substring of a column that is delimited by a character.

For example, in this dataframe

```julia
df = DataFrame(
     id=["1", "1", "2"],
     string=["A.B.C.D.JUNK", "A.B.C.JUNK", "A.B.JUNK"]
)

```

I would like a create a new column that is created by splitting the cell called string by the “.” delimiter and removing the first and last sections of the field.

So the result should look like the following

```julia
df = DataFrame(
     id=["1", "1", "2"],
     string=["A.B.C.D.JUNK", "A.B.C.JUNK", "A.B.JUNK"],
     newstring=["B.C.D","B.C","B"]
)

```

I’ve tried this but it doesn’t seem to work

```julia
df.newstring .== join.(split.(df.string, ".")[2:end-1], ".")

```

Any suggestions

---

<div class="post-metadata">

### Author: ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)
#### Post date: [September 25, 2023, 2:01am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/2 "2023-09-25T02:01:45Z")

</div>

Here’s my attempt at turning `"A.B.C.D.JUNK"` into `["B.C.D","B.C","B"]`. I split it up into multiple lines for clarity. You can collapse it back to a one-liner later.

```julia
s = "A.B.C.D.JUNK"
ps = split(s, ".")
middle = ps[2:end-1]
newstring = reduce(middle) do m, a
	if ismissing(m)
		return [a]
	else
		return ["$(m[1]).$a", m...]
	end
end

```

The variable `newstring` should be `["B.C.D","B.C","B"]`. The main difference between your attempt and mine is `join` vs `reduce`.

---

<div class="post-metadata">

### Author: ![jonjilla](https://avatars.discourse-cdn.com/v4/letter/j/7ba0ec/32.png) [@jonjilla](https://discourse.julialang.org/u/jonjilla)
#### Post date: [September 25, 2023, 3:10am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/3 "2023-09-25T03:10:26Z")

</div>

@g-gundam I’m not sure how this works to update the data frame? working on one string at a time, the join(split) works fine, but I’m having trouble updating the entire column in the dataframe.

---

<div class="post-metadata">

### Author: ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)
#### Post date: [September 25, 2023, 3:34am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/5 "2023-09-25T03:34:33Z")

</div>

@jonjilla - I misunderstood your initial intent. I’m going to try something else. One moment.

Try this:

```julia
df2 = DataFrame(
    id=["1", "1", "2"],
    string=["A.B.C.D.JUNK", "A.B.C.JUNK", "A.B.JUNK"]
)
df2.newstring = map(df2.string) do s
    join(split(s, ".")[2:end-1], ".")
end

```

---

<div class="post-metadata">

### Author: ![jonjilla](https://avatars.discourse-cdn.com/v4/letter/j/7ba0ec/32.png) [@jonjilla](https://discourse.julialang.org/u/jonjilla)
#### Post date: [September 25, 2023, 5:05am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/6 "2023-09-25T05:05:49Z")

</div>

Thanks, that seems to get me what I need

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [September 25, 2023, 6:05am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/7 "2023-09-25T06:05:21Z")

</div>

> [@jonjilla](#):
>
> I’ve tried this but it doesn’t seem to work

A solution along the lines of your attempt could be this.

```julia
newstr=join.(getindex.(split.(df.string, "."),range.(2,lastindex.(split.(df.string, ".")).-1)),'.')

```

As you can easily see, it is not, in any respect, preferable to the solution already proposed.

---

<div class="post-metadata">

### Author: ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)
#### Post date: [September 25, 2023, 6:11am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/8 "2023-09-25T06:11:04Z")

</div>

Just because you can, doesn’t mean you should. 😛  
Sometimes, Julia reminds me of Perl, and I mean that affectionately. I liked Perl and how flexible and playful it was in its time.

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [September 25, 2023, 6:31am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/9 "2023-09-25T06:31:20Z")

</div>

a middle

```julia
vh=findfirst.('.',df.string)
vt=findfirst.('.',reverse.(df.string))

map(((s, h,t),)->chop(s,head=h,tail=t), zip(df.string, vh,vt))
#or
newstring = map(df.string, vh,vt) do s, h, t
	chop(s,head=h,tail=t)
end

```

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [September 25, 2023, 6:42am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/10 "2023-09-25T06:42:45Z")

</div>

```julia
replace.(df.string, r"^\w+\."=>"",r"\.\w+$"=>"")

```

```julia
replace.(df.string, r"^\w+\.(.+)\.\w+$"=>s"\1")

```

---

<div class="post-metadata">

### Author: ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)
#### Post date: [September 25, 2023, 8:06am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/11 "2023-09-25T08:06:11Z")

</div>

> [@rocco\_sprmnt21](#):
>
> ```julia
> vh=findfirst.('.',df.string)
> vt=findfirst.('.',reverse.(df.string))
> 
> ```

This is a bit tricky, as you have:

```julia
julia> str = "ł.ą.ź"
"ł.ą.ź"

julia> vh=findfirst('.',str)
3

julia> vt=findlast('.',str)
6

julia> chop(str, head=vh, tail=vt) # wrong
""

julia> chop(str[vh+1:vt]) # correct, +1 because we know that `.` is ASCII
"ą"

```

And the issue is related to byte vs character indexing differences. See [The String, or There and Back Again | Blog by Bogumił Kamiński](https://bkamins.github.io/julialang/2020/08/13/strings.html)

For ASCII strings things would work.

---

<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: [September 25, 2023, 8:37am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/12 "2023-09-25T08:37:54Z")

</div>

> [@bkamins](#):
>
> ```julia
> julia> vt=findlast('.',str)
> 6
> 
> julia> chop(str, head=vh, tail=vt) # wrong
> ""
> 
> ```

This wouldn’t work even with no non-ASCII as `tail` parameter is count from end of string, and `vt` is an index from beginning of string.

In any case, another mini-idea is to use SubString to avoid copying (ADDED: this code has a bug. see next 2 posts):

```julia
julia> map(df2.string) do s
       SubString(s,findfirst('.',s)+1:findlast('.',s)-1)
       end
3-element Vector{SubString{String}}:
 "B.C.D"
 "B.C"
 "B"

```

As Bogumil suggested, the +1 good for index math because of ASCII ‘.’ and the -1 is good because we want to index last byte of previous codepoint.

---

<div class="post-metadata">

### Author: ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)
#### Post date: [September 25, 2023, 9:50am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/13 "2023-09-25T09:50:36Z")

</div>

> [@Dan](#):
>
> This wouldn’t work even with no non-ASCII

ah - right.

> [@Dan](#):
>
> and the -1 is good because we want to index last byte of previous codepoint.

It would not work, because the character just before the last `.` could be muliti-byte:

```julia
julia> s = ".ą."
".ą."

julia> SubString(s,findfirst('.',s)+1:findlast('.',s)-1)
ERROR: StringIndexError: invalid index [3], valid nearby indices [2]=>'ą', [4]=>'.'

```

(things are hard :(, I made such mistakes numerous times unfortunately, I work in the Polish language where such cases are super common so I am sensitive to them). You need to `chop` or take `prevind`

---

<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: [September 25, 2023, 9:58am UTC](https://discourse.julialang.org/t/create-string-out-of-substring-in-dataframe/104206/14 "2023-09-25T09:58:38Z")

</div>

…things are indeed confusing. Just to keep working code in the thread, with `prev_ind`:

```julia
julia> map(df2.string) do s
       SubString(s,findfirst('.',s)+1:prevind(s,findlast('.',s)))
       end

```
