This commit is contained in:
Matthieu Dubuget 2022-04-10 11:58:17 +02:00
parent 253633f09d
commit 42b8fa388b
6 changed files with 216 additions and 64 deletions

View File

@ -1,9 +1,9 @@
Nombres Nombres
========= =========
Convert ints into french. Convert integers into french.
Provided as a 1-function library, and a basic command-line utility (`nbr` — will Provided as a 1-function library and a basic command-line utility (`nbr` — will
certainly be renamed to something longer and less likely to name clash). certainly be renamed to something longer and less likely to name clash).
More advanced functionnalities could be added when needed. Here are some More advanced functionnalities could be added when needed. Here are some

View File

@ -4,14 +4,16 @@ let rec parse_and_print () =
input_line stdin |> function input_line stdin |> function
| "q" | "Q" -> () | "q" | "Q" -> ()
| "h" | "?" | "H" -> | "h" | "?" | "H" ->
print_endline "Je n'accepte que des entiers positifs. Et pas trop grands…\n'q' ou 'Q' pour quitter."; print_endline
"Je n'accepte que des entiers positifs. Et pas trop grands…\n\
'q' ou 'Q' pour quitter.";
flush stdout; flush stdout;
parse_and_print () parse_and_print ()
| str -> | str ->
str |> int_of_string str |> int_of_string
|> (fun i -> |> (fun i ->
match i with match i with
| i -> i |> Nombres.nombre_of_int |> print_endline | i -> i |> Nombres.nombre |> print_endline
| exception _ -> ()) | exception _ -> ())
|> parse_and_print |> parse_and_print

View File

@ -1,11 +1,19 @@
(lang dune 2.8) (lang dune 3.0)
(name nombres)
(version 0.9)
(generate_opam_files true) (generate_opam_files true)
(name nombres)
(source (github ttamttam/nombres))
(license ISC)
(authors "Matthieu Dubuget")
(maintainers "matthieu.dubuget@gmail.com")
(package (package
(name nombres) (name nombres)
(synopsis "Conversion of integers to french.")
(description (description
"\| Convert ints into french. "\| Convert integers into french.
"\| "\|
"\| Some references: "\| Some references:
"\| - https://leconjugueur.lefigaro.fr/frlesnombres.php "\| - https://leconjugueur.lefigaro.fr/frlesnombres.php

View File

@ -1,2 +1,4 @@
(library (library
(name nombres)) (name nombres)
(public_name nombres)
(libraries fmt))

View File

@ -1,56 +1,188 @@
let rec nombre_of_int = function type options =
| 0 -> "zéro" | Septante
| 1 -> "un" | Huitante
| 2 -> "deux" | Nonante
| 3 -> "trois" | Belgique (* Septante Nonante *)
| 4 -> "quatre" | VVF (* Septante Huitante Nonante *)
| 5 -> "cinq"
| 6 -> "six"
| 7 -> "sept"
| 8 -> "huit"
| 9 -> "neuf"
| 10 -> "dix"
| 11 -> "onze"
| 12 -> "douze"
| 13 -> "treize"
| 14 -> "quatorze"
| 15 -> "quinze"
| 16 -> "seize"
| 20 -> "vingt"
| 30 -> "trente"
| 40 -> "quarante"
| 50 -> "cinquante"
| 60 -> "soixante"
| 80 -> "quatre-vingts"
| 100 -> "cent"
| 1000 -> "mille"
| n when n < 70 -> jusqua_70 n
| n when n < 80 -> jusqua_100 "soixante" n
| n when n < 100 -> jusqua_100 "quatre-vingt" n
| n when n < 1_000 -> jusqua_1000 n
| n when n < 1_000_000 -> jusqua_1000000 n
| _ -> "--------------------"
and jusqua_70 n = let int_of_options = function
let dizaine = nombre_of_int (n / 10 * 10) in | Septante -> 0x1
let unite = n mod 10 in | Huitante -> 0x2
[ dizaine; nombre_of_int unite ] | Nonante -> 0x8
|> String.concat (if unite = 1 then " et " else "-") | Belgique -> 0x1 lor 0x8
| VVF -> 0x1 lor 0x2 lor 0x8
and jusqua_100 dizaine n = type mode = [ `Belgique | `VVF | `France ]
let unite = n mod 10 in
[ dizaine; nombre_of_int (n mod 20) ]
|> String.concat (if unite = 1 && n < 80 then " et " else "-")
and jusqua_1000 n = let options_of_mode = function
let centaine = n / 100 and reste = n mod 100 in | `Belgique -> [ Belgique ]
let cent = if centaine > 1 && reste = 0 then "cents" else "cent" in | `VVF -> [ VVF ]
((if centaine = 1 then [ cent ] else [ nombre_of_int centaine; cent ]) | `France -> []
@ if reste = 0 then [] else [ nombre_of_int reste ])
|> String.concat " "
and jusqua_1000000 n = let int_of_mode m =
let milliers = n / 1000 and reste = n mod 1000 in m |> options_of_mode |> List.map int_of_options
((if milliers = 1 then [ "mille" ] else [ nombre_of_int milliers; "mille" ]) |> ListLabels.fold_left ~f:( + ) ~init:0
@ if reste = 0 then [] else [ nombre_of_int reste ])
|> String.concat " " let mode_of_int = function
| 0 -> `France
| 1 -> `Belgique
| 2 -> `VVF
| _ -> assert false
let opts options lst = List.exists (fun opt -> List.mem opt options) lst
let nombre ?(options = []) n =
let has_opts = opts options in
if n = min_int then invalid_arg "Nombre hors domaine"
else
(* if debug then Fmt.pr "@[<v 2>nombre %d:@," n; *)
let rec schu =
[|
"";
"un";
"deux";
"trois";
"quatre";
"cinq";
"six";
"sept";
"huit";
"neuf";
"dix";
"onze";
"douze";
"treize";
"quatorze";
"quinze";
"seize";
|]
and schd =
[|
"";
"dix";
"vingt";
"trente";
"quarante";
"cinquante";
"soixante";
"soixante";
|]
and nombre_of_int ?(singular = false) ?(accu = []) current () =
match current with
| 0 ->
if accu <> [] then accu |> List.rev |> String.concat " "
else "zéro"
| n when n < 0 -> nombre_of_int ~accu (-n) ()
| n when n < 17 -> unroll (schu.(n) :: accu)
| n when n mod 10 = 0 && n < 61 -> unroll (schd.(n / 10) :: accu)
| 80 ->
let nom, noms =
if has_opts [ Huitante; VVF ] then ("huitante", "huitante")
else ("quatre-vingt", "quatre-vingts")
in
unroll ((if singular then nom else noms) :: accu)
| 100 -> unroll ("cent" :: accu)
| 1000 -> unroll ("mille" :: accu)
| n when n < 70 ->
let dizaines = nombre_of_int (n / 10 * 10) () in
let unites = n mod 10 in
let accu =
([
dizaines;
(if unites = 1 then " et " else "-");
nombre_of_int unites ();
]
|> String.concat "")
:: accu
in
unroll accu
| n when n < 80 ->
let unites = n mod 10 in
let accu =
if has_opts [ Septante; Belgique; VVF ] then
([
(if n < 70 then "soixante" else "septante");
(if unites = 1 && n < 80 then " et "
else if unites > 0 then "-"
else "");
(if unites > 0 then nombre_of_int unites () else "");
]
|> String.concat "")
:: accu
else
([
"soixante";
(if unites = 1 && n < 80 then " et " else "-");
nombre_of_int (n mod 20) ();
]
|> String.concat "")
:: accu
in
unroll accu
| n when n < 100 ->
let unites = n mod 10 in
let accu =
if has_opts [ Huitante; VVF ] && n < 90 then
([
"huitante";
(if unites = 1 then " et " else if unites > 0 then "-" else "");
(if unites > 0 then nombre_of_int unites () else "");
]
|> String.concat "")
:: accu
else if has_opts [ Nonante; VVF; Belgique ] && n >= 90 then
([
"nonante";
(if unites = 1 then " et " else if unites > 0 then "-" else "");
(if unites > 0 then nombre_of_int unites () else "");
]
|> String.concat "")
:: accu
else
([
"quatre-vingt";
(if unites = 1 && n < 80 then " et " else "-");
nombre_of_int (n mod 20) ();
]
|> String.concat "")
:: accu
in
unroll accu
| n when n < 1_000 -> jusqua_x ~singular accu 100 ~nom:"cent" ~un:false n
| n when n < 1_000_000 -> jusqua_x accu 1000 ~nom:"mille" ~un:false n
| n when n < 1_000_000_000 ->
jusqua_x accu 1_000_000 ~nom:"million" ~un:true n
| n when n < 1_000_000_000_000 ->
jusqua_x accu 1_000_000_000 ~nom:"milliard" ~un:true n
| n when n < 1_000_000_000_000_000 ->
jusqua_x accu 1_000_000_000_000 ~nom:"billion" ~un:true n
| n when n < 1_000_000_000_000_000_000 ->
jusqua_x accu 1_000_000_000_000_000 ~nom:"billiard" ~un:true n
| n when n <= max_int ->
jusqua_x accu 1_000_000_000_000_000_000 ~nom:"trillion" ~un:true n
| _ -> assert false
and unroll accu = List.rev accu |> String.concat " "
and jusqua_x ?(singular = false) accu lim ~nom ~un n =
let un = if un then "un" else "" in
let noms =
match (nom, singular) with
| "mille", _ -> "mille"
| nom, true -> nom
| nom, false -> nom ^ "s"
in
let count = n / lim and reste = n mod lim in
let accu =
match count with
| 1 -> nom :: un :: accu |> List.filter (( <> ) "")
| _ ->
let noms = if lim = 100 && reste <> 0 then nom else noms in
noms
:: nombre_of_int ~singular:(singular || lim = 1000) count ()
:: accu
in
nombre_of_int ~singular ~accu reste ()
in
nombre_of_int n ()

View File

@ -1,15 +1,22 @@
# This file is generated by dune, edit dune-project instead # This file is generated by dune, edit dune-project instead
opam-version: "2.0" opam-version: "2.0"
version: "0.9"
synopsis: "Conversion of integers to french."
description: """ description: """
Convert ints into french. Convert integers into french.
Some references: Some references:
- https://leconjugueur.lefigaro.fr/frlesnombres.php - https://leconjugueur.lefigaro.fr/frlesnombres.php
- https://www.miakinen.net/vrac/nombres - https://www.miakinen.net/vrac/nombres
- https://www.dcode.fr/ecriture-nombre-lettres - https://www.dcode.fr/ecriture-nombre-lettres
""" """
maintainer: ["matthieu.dubuget@gmail.com"]
authors: ["Matthieu Dubuget"]
license: "ISC"
homepage: "https://github.com/ttamttam/nombres"
bug-reports: "https://github.com/ttamttam/nombres/issues"
depends: [ depends: [
"dune" {>= "2.8"} "dune" {>= "3.0"}
"odoc" {with-doc} "odoc" {with-doc}
] ]
build: [ build: [
@ -26,3 +33,4 @@ build: [
"@doc" {with-doc} "@doc" {with-doc}
] ]
] ]
dev-repo: "git+https://github.com/ttamttam/nombres.git"