# How to parse a string with ranges?

**URL:** https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288
**Category:** General Usage
**Tags:** strings, repl, parsing
**Created:** [April 9, 2023, 10:30pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288 "2023-04-09T22:30:48Z")
**Posts on this page:** 8
**Page:** 1

<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: [April 9, 2023, 10:30pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/1 "2023-04-09T22:30:49Z")

</div>

I would like to avoid using `eval` to parse some user input from the REPL that expects lists of integers and may contain some ranges, as in this MWE:

```julia
# INPUT:
str = "1 3:3:12 18 20"

# OUTPUT: 
v = eval(Meta.parse("[" * join(split(str),';') * "]"))

```

The above is fine with me, but a malicious user may erase the whole disk with this kind of thing, [as illustrated here](https://discourse.julialang.org/t/parse-vector-from-string/10728/16).

So my question is, is there an easy way to parse a string with ranges?  
Say, a string like: `"3:3:12"`

Thank you.

---

<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: [April 9, 2023, 10:38pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/2 "2023-04-09T22:38:54Z")

</div>

some ideas for inspiration:

```julia
julia> a = "3:3:12"
"3:3:12"

julia> Base._colon(parse.(Int, split(a, ':'))...)
3:3:12

```

---

<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: [April 9, 2023, 10:41pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/3 "2023-04-09T22:41:10Z")

</div>

Thanks @jling, I was not aware of this internal tool.

---

<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: [April 9, 2023, 10:44pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/4 "2023-04-09T22:44:19Z")

</div>

Using `eval` is definitely not a suggested path.

But stopping short at parsing like so:

```julia
julia> vv = Meta.parse("[" * join(split(str),';') * "]")
:([1; 3:3:12; 18; 20])

julia> dump(vv)
Expr
  head: Symbol vcat
  args: Array{Any}((4,))
    1: Int64 1
    2: Expr
      head: Symbol call
      args: Array{Any}((4,))
        1: Symbol :
        2: Int64 3
        3: Int64 3
        4: Int64 12
    3: Int64 18
    4: Int64 20

```

and then filtering the resulting expression (maybe macro authoring tools can help) and evaluating safely looks promising.

---

<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: [April 9, 2023, 11:20pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/5 "2023-04-09T23:20:01Z")

</div>

FWIW, a three-liner around @jling’s idea, to replace `eval` in the OP example (edited with Henrique’s solution, and using `unique`):

```julia
# INPUT:
str = "1 3:3:12 18 20"

# CHECK INPUT: 
!all(isnumeric, filter(x -> x ∉ (':',' '), str)) && throw(DomainError(str, "Only integers>0 and ranges, pls!"))

# OUTPUT
v = reduce(unique ∘ vcat, [(':' ∈ s ? (:)(parse.(Int, split(s, ':'))...) : parse(Int,s)) for s in split(str)])

```

---

<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: [April 9, 2023, 11:39pm UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/6 "2023-04-09T23:39:50Z")

</div>

Maybe checking the length of ranges to prevent allocation of too much memory is also a good idea.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 10, 2023, 1:18am UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/7 "2023-04-10T01:18:09Z")

</div>

> ```julia
> julia> Base._colon(parse.(Int, split("3:3:12", ':'))...)
> 3:3:12
> 
> ```

This should not be the accepted answer. `_colon` is undocumented and underscore-prefixed, it should not be used in production code. A better solution (considering that is okay to throw an exception if the format is incorrect) is:

```julia
julia> (:)(parse.(Int, split("3:3:12", ':'))...)
3:3:12

```

---

<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: [April 10, 2023, 4:48am UTC](https://discourse.julialang.org/t/how-to-parse-a-string-with-ranges/97288/8 "2023-04-10T04:48:31Z")

</div>

I don’t know if it is among the possible cases, but in the case of input with spaces before and/or after ‘:’

```julia
istr=" 2 5 3 : 7 6 2 : 3: 9 12 2 :4 :11 23 1:2:11"

rs=findall(r"\d+ *: *\d+( *: *\d+)*",istr)
rngs=getindex.([istr],rs)
ints=replace(istr,(rngs.=>"")...)
parse.(Int,split(ints))

function parserange(rstr)
    rng=parse.(Int,split(rstr,":"))
    if length(rng)==2 insert!(rng,2,1) end
    range(;zip([:start,:step,:stop],rng)...)
end

parserange.(rngs)

```

PS

I’d be curious to know alternative regular expressions to the one I found to locate the ranges and, if possible, some expressions to find the integers that are not arguments of the ranges (i.e. close -spaces apart- to ‘:’)
