Change middle character of a string

Let’s say i have a string “abcde”.
I want to change the 3th character from ‘c’ to ‘x’.
Can i use a library function ?

Check out the String.mapi function, it can do the job.

If i’m correct strings are immutable so the whole string is copied. Time n.
I had thought of converting a string to an array of bytes. Changing one byte in the array and converting the array of bytes to a string. The conversion will also take a time n.
And i have no clue how to do the conversion. [ I know how to do it in dlang …]

You will find all the answers in the String and Bytes module documentation.

I think you need to rethink this a bit, because there’s two possible things you want:

  1. You want to change the second character
  2. You want to change the second byte

With ASCII the former and the latter is the same, but in the presence of Unicode, what would you expect to change in the string " :fr: :denmark::ukraine:"? Whereas if you just have a sequence of raw bytes, without any additional meaning ascribed to them and want to change the second byte, then Bytes.set exists, which will do what you want.

2 Likes

Can’t do it in Java, either. Look: maybe OCaml isn’t right for you. Maybe functional languages aren’t your cup of tea.

I wouldn’t say that. Alain seems to be eager to learn and having fun (look at the lazy Fibonacci thread). It takes time to change from an imperative/OOP mindset to an FP mindset.

3 Likes

Strings in OCaml are immutable. Though I’ve never used Dlang, I would guess that because it bills itself as a C alternative that strings are mutable there.

@yawaramin mentioned you can use Bytes.{of_string|to_string} to convert to and from strings, but as you note both of these operations are O(n), and so using something like String.mapi (also recommended by @yawaramin) is probably better. To do what you mentioned in the OP, I would write something like:

String.mapi (fun i c -> if i = 2 then 'x' else c) "abcde"

If you’re willing to mess around with the C FFI, you could probably get away with directly mutating strings that way (IIRC we used to do something like this in Revery), but I highly recommend against this. If you need to do a ton of mutation, using bytes is probably smarter.

[ Sidenote, dlang strings are immutable, but can very easily be converted to another datatype ]

I have a theoretical/philosophical question. Would it be possible to create a mutable string “type” with log(n) character lookup time for modification, even if it’s unwise/unusefull.
How would one do this in wordings ?

Zach, I believe this is incorrect. I checked the source and the safe conversion operation seems to be doing a blit (copy) and then a primitive operation to recast a string as bytes.

Actually, that is exactly the relationship between string and bytes in OCaml. I highly recommend at least skimming through the module docs for String and Bytes, they will give you an idea of what’s possible.

1 Like

I’m slightly confused. Looking at the source of the operations, they both perform a copy, which is at least O(n), no? Diving further into the source, copy calls unsafe_blit, which is the C function caml_blit_bytes. This is effectively an OCaml wrapper on top of memmove. memmove has to iterate over each byte, which is O(n), is it not?

The link between string and byte is module Char.

Ah, so I misunderstood, caml_blit_bytes is ultimately doing a byte-by-byte copy. So yes, it is O(n). To do the change safely though, we will need to do it on a copy of the string, so I don’t think we can avoid at least one O(n) copy operation.

1 Like

I would love not to have to see this kind of gatekeeping comments in this forum. I’d encourage assuming questions are asked out of curiosity, in order to foment a productive discussion.

7 Likes

I don’t see any problem as proponent of free speech.
PS1, I think reading a good readable book on lambda calculus would help me thinking “ocaml way”, instead of “procedural way”.
PS2, A totally different question, since a reference was made towards java, any ideas/thoughts towards scala ?

1 Like

PS2: OCaml is a functional programming language with some OOP capabilities. Scala is an object-functional language. Their philosophies are different. E.g. what do you think happens with the following code snippet in both the languages:

if true then 1 else ""

In OCaml it’s a type error. In Scala this is a valid expression and its type is Any, which is the common supertype of Int and String, the types on either branch of the if expression.

2 Likes

Ocaml changed my way of thinking in three ways.

  1. I think more in function of types then classes.
  2. My loops became tail-recursive calls.
  3. All my ifs have an else clause.

I don’t think so. Lambda calculus is extremely primitive w.r.t OCaml and OCaml has a rich type system while lambda calculus (in its basic form) is untyped. Similarly, reading about Turing machines won’t help you much to master a richly-typed imperative language. I’d rather advise an introductory book about functional programming in OCaml. This one is said to be good.

3 Likes

There are two ways to change something in an immutable data and one of them is evil.
The non-evil way and probably the most efficient in String interface is mapi as suggested before.
The evil way is to unsafely cast to Bytes then recast to String after the change, this is O(1) but breaks any kinds of guarantees that come with a string’s immutability.
It’s not something you go for unless you can assure those guarantees yourself or assure you’re not making any assumptions based on them. It’s something you go for if you’re really hurting in performance, and in that case you might want to re-assess your use of String to begin with.

I wholly agree. Another possibility would be OCaml Programming: Correct + Efficient + Beautiful which is a tad more advanced.

2 Likes