string to list of char
Asked Answered
A

7

23

I want to write a function that taking a string and return a list of char. Here is a function, but I think it is not do what I want ( I want to take a string and return a list of characters).

let rec string_to_char_list s =
    match s with
      | "" -> []
      | n -> string_to_char_list n
Arnold answered 9/4, 2012 at 3:53 Comment(2)
On the plus side, this will work for an empty string! You need to handle non-empty strings a little better. Since OCaml doesn't let you destructure a string with pattern matching, a function like this is probably going to use an index (an integer) to get at the characters in the string.Responsiveness
| n -> string_to_char_list n that's an infinite loop for you. Never recurse with the same parameter you got in!Francisco
F
31

Aside, but very important:

Your code is obviously wrong because you have a recursive call for which all the parameters are the exact same one you got in. It is going to induce an infinite sequence of calls with the same values in, thus looping forever (a stack overflow won't happen in tail-rec position).


The code that does what you want would be:

let explode s =
  let rec exp i l =
    if i < 0 then l else exp (i - 1) (s.[i] :: l) in
  exp (String.length s - 1) []

Source: http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#strings


Alternatively, you can choose to use a library: batteries String.to_list or extlib String.explode

Francisco answered 9/4, 2012 at 6:56 Comment(0)
M
28

Try this:

let explode s = List.init (String.length s) (String.get s)
Mongo answered 18/9, 2018 at 18:49 Comment(1)
Note: List.init added in OCaml 4.06.0.Caparison
N
6

Nice and simple:

let rec list_car ch = 
  match ch with
  | "" -> []
  | ch -> String.get ch 0 :: list_car (String.sub ch 1 (String.length ch - 1));;
Nate answered 12/6, 2014 at 0:3 Comment(1)
Somewhat inefficient, though, as a new string is generated at each iteration.Seamaid
S
6

As of OCaml 4.07 (released 2018), this can be straightforwardly accomplished with sequences.

let string_to_char_list s =
  s |> String.to_seq |> List.of_seq

It may help to see an implementation of creating a sequence for a string. In the standard library, this is done by way of the bytes type, but we can implement a simple function to do the same directly with a string.

let string_to_seq s =
  let len = String.length s in
  let rec aux i () =
    if i = len then Seq.Nil
    else Seq.Cons (s.[i], aux @@ i + 1)
  in
  aux 0

Or using exceptions:

let string_to_seq s =
  let rec aux i () =
    match String.get s i with
    | ch -> Seq.Cons (ch, aux @@ i + 1)
    | exception Invalid_argument _ -> Seq.Nil
  in
  aux 0

We can avoid the nested inner function if we provide a start index argument with a default value of 0.

let rec string_to_seq ?(i=0) s () =
  match String.get s i with
  | ch -> Seq.Cons (ch, string_to_seq ~i: (i+1) s)
  | exception Invalid_argument _ -> Seq.Nil

This lets us call simply string_to_seq "hello world" but also to specify an initial starting sequence great than 0.

Seamaid answered 27/10, 2022 at 5:1 Comment(0)
C
3

How about something like this:

let string_to_list str =
  let rec loop i limit =
    if i = limit then []
    else (String.get str i) :: (loop (i + 1) limit)
  in
  loop 0 (String.length str);;

let list_to_string s =
  let rec loop s n =
    match s with
      [] -> String.make n '?'
    | car :: cdr ->
       let result = loop cdr (n + 1) in
       String.set result n car;
       result
  in
  loop s 0;;
Consecutive answered 10/8, 2015 at 21:47 Comment(0)
E
1

Here is an Iterative version to get a char list from a string:

let string_to_list s = 
  let l = ref [] in
  for i = 0 to String.length s - 1 do
    l := (!l) @ [s.[i]]
  done;
  !l;;
Easter answered 18/12, 2018 at 11:1 Comment(1)
@ in a loop or a recursive function call tends to be a bad idea for efficiency. Suggest you build up your list in reverse: l := s[.[i] :: !l, and then return List.rev !l.Seamaid
P
1

My code, suitable for modern OCaml:

let charlist_of_string s =
  let rec trav l i =
    if i = l then [] else s.[i]::trav l (i+1)
  in
  trav (String.length s) 0;;

let rec string_of_charlist l =
  match l with
    [] -> "" 
  | h::t -> String.make 1 h ^ string_of_charlist t;;
Programme answered 28/9, 2020 at 15:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.