This is part of my first OCaml program.
Its job is to replace a set of placeholder characters with umlauts. Taking the German word
Ruebe as an example, the program turns it into
Rübe. Other examples are
Moewe -> Möwe and
aendern -> ändern
Generally, everytime the program encounters the characters
ue it turns them into umlauts. There is an exception though: If the preceding character is a vowel, it does not change the word. This ensures words like
Treue remain as they are (since there is no word
I've used the library
Re2 for regular expressions.
Re2 doesn't implement lookarounds, which was my first thought for checking for preceding vowels. This is the reason for the function
I am happy for all suggestions, especially if they help make the code more idiomatic or simpler.
To compile the program, I used the command
ocamlbuild -use-ocamlfind -package re2 -package core -tag thread myCompiledFile.byte
open Core.Std open Re2.Std open Re2.Infix (* If the word contains an umlaut placeholder like "ue" we replace that with the proper umlaut "ü". Except if there is a vowel directly before the placeholder like in "Treue" *) let placeholders_to_umlauts = [("ue", "ü"); ("oe","ö"); ("ae","ä"); ("Ue", "Ü"); ("Oe","Ö"); ("Ae","Ä")] (* A regex that matches a vowel *) let vowel = ~/"[aeiou]" (* Applies a list of changes to a word *) let rec apply_changes word changes = match changes with |  -> word | change :: rest -> apply_changes (change word) rest (* Replaces replace_this with replacement inside the text if the preceding character not a vowel. Since Re2 doesn't implement lookarounds we can't use a negative lookbehind *) let replace_if_not_after_vowel replace_this replacement text = Re2.replace_exn ~/replace_this text ~f:(fun regex_match -> (* Returns true if there is a vowel at the given position in the text *) let is_vowel text pos = if pos >= 0 && pos < String.length text then let maybe_vowel = String.get text pos in Re2.matches vowel (Char.to_string maybe_vowel) else false in (* Get the position in the text where the regex matched *) let match_pos, _ = Re2.Match.get_pos_exn ~sub:(`Index 0) regex_match in (* Replace the placeholder if doesn't follow a vowel *) if is_vowel text (match_pos -1 ) then replace_this else replacement ) let change_word word = (* Those are the changes that we will apply to the word *) let changes = List.map placeholders_to_umlauts ~f:( fun (placeholder, umlaut) -> replace_if_not_after_vowel placeholder umlaut ) in apply_changes word changes let () = (* We want to change this word into "Übergrößenträgertreue" *) let word = "Uebergroeßentraegertreue" in let new_word = change_word word in printf "new word: %s\n" new_word