Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] Printf and format
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Xavier Leroy <xavier.leroy@i...>
Subject: Re: [Caml-list] Printf and format
> Is there a way to transform string to ( 'a, out_channel, unit, unit)
> format. I need this function to use it with something like :
> 
> Printf.printf (my_fun "X, Y") "coucou";;

No, not in a type-safe manner.  The type of a format string depends on
the "%" specifiers found in the string itself, and OCaml can't infer
or check types at run-time.

However, for the purpose of internationalization, the following
operation suffices: given a (compile-time constant) format and a
(dynamically computed) string, check that the string can be viewed as
a format with the same format type as the constant format, and return
the string as a format.  

In OCaml 3.06, this can be done as follows:

  let re_fmt =
    Str.regexp "%[#0-9.*+ -]*[lnL]?[sScCdioxXunfeEgGFbBatn[]"

  let string_of_format (s : ('a, 'b, 'c) format) = (Obj.magic s : string)

  let extract_formats s =
    List.fold_right
      (fun part accu ->
        match part with Str.Text _ -> accu | Str.Delim d -> d :: accu)
      (Str.full_split re_fmt s) []

  let conv_format (src: ('a, 'b, 'c) format) (dst: string) =
    if extract_formats (string_of_format src) = extract_formats dst
    then (Obj.magic dst : ('a, 'b, 'c) format)
    else failwith "conv_format"

Remark 1: yes, there's a lot of "Obj.magic" in this code, and yes,
this is a deadly sin, but in this particular instance it is all
type-safe nonetheless.

Remark 2: the matching of the two formats can be relaxed, e.g.
the code above will not allow the conversion of "%6d" into "%8x",
although both formats have the same type.  This is left as an exercise
for the reader.  But for internationalization purposes, I doubt
you need that additional flexibility.

Then, assuming you have a function "gettext : string -> string" to translate
strings according to the user-selected language, you can extend it to
formats as follows:

  let getformat f = conv_format f (gettext (string_of_format f))

and use it with printf functions like this:

  printf (getformat "My name is %s and I'm %d years old") "Bob" 12

> you read my mind. Indeed, the question concern an internationalization
> module ( let's call libgettext-ocaml ). It is basically a binding of
> gettext. 

I hope the above is enough to get you off the ground.

- Xavier Leroy

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners