Compare commits
22 Commits
1569132c6c
...
master
Author | SHA1 | Date | |
---|---|---|---|
052edf14f5 | |||
9376ca48ea | |||
42b8fa388b | |||
253633f09d | |||
4658be437b | |||
e484d4a777 | |||
dd0bfdb5d8 | |||
1ac1681bcd | |||
6ae72e4fc5 | |||
5bb8a94c2f | |||
8cfbfb6274 | |||
469c836ea0 | |||
8877cc54cc | |||
5e50900165 | |||
abd5278719 | |||
f88594dd12 | |||
c50e512184 | |||
ad72fdeb0b | |||
b324162a12 | |||
d2cf323e19 | |||
8ea4705c17 | |||
7529a7ed15 |
50
.github/workflows/blank.yml
vendored
Normal file
50
.github/workflows/blank.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: CI
|
||||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
ocaml-compiler:
|
||||
- 4.12.x
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
||||
uses: ocaml/setup-ocaml@v2
|
||||
with:
|
||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
||||
|
||||
- run: opam install . --deps-only
|
||||
|
||||
- run: opam exec -- dune build
|
||||
|
||||
- name: Upload a Windows Build Artifact
|
||||
uses: actions/upload-artifact@v2.2.3
|
||||
if: runner.os == 'Windows'
|
||||
with:
|
||||
name: nbr-win32
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: _build/install/default/bin/nbr.exe
|
||||
retention-days: 1
|
||||
|
||||
- name: Upload a Linux Build Artifact
|
||||
uses: actions/upload-artifact@v2.2.3
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
name: nbr-linux
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: _build/install/default/bin/nbr
|
||||
retention-days: 1
|
10
README.md
10
README.md
@ -1,9 +1,15 @@
|
||||
Nombres
|
||||
=========
|
||||
|
||||
Convert ints into french.
|
||||
Convert integers into french.
|
||||
|
||||
Some references:
|
||||
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).
|
||||
|
||||
More advanced functionnalities could be added when needed. Here are some
|
||||
references:
|
||||
- https://leconjugueur.lefigaro.fr/frlesnombres.php
|
||||
- https://www.miakinen.net/vrac/nombres
|
||||
- https://www.dcode.fr/ecriture-nombre-lettres
|
||||
|
||||
[](https://github.com/ttamttam/nombres/actions/workflows/blank.yml)
|
||||
|
4
bin/dune
Normal file
4
bin/dune
Normal file
@ -0,0 +1,4 @@
|
||||
(executable
|
||||
(name nbr)
|
||||
(public_name nbr)
|
||||
(libraries nombres))
|
20
bin/nbr.ml
Normal file
20
bin/nbr.ml
Normal file
@ -0,0 +1,20 @@
|
||||
let rec parse_and_print () =
|
||||
print_string "Entier (Ou [Q]uitter [H]elp) ? > ";
|
||||
flush stdout;
|
||||
input_line stdin |> function
|
||||
| "q" | "Q" -> ()
|
||||
| "h" | "?" | "H" ->
|
||||
print_endline
|
||||
"Je n'accepte que des entiers positifs. Et pas trop grands…\n\
|
||||
'q' ou 'Q' pour quitter.";
|
||||
flush stdout;
|
||||
parse_and_print ()
|
||||
| str ->
|
||||
str |> int_of_string
|
||||
|> (fun i ->
|
||||
match i with
|
||||
| i -> i |> Nombres.nombre |> print_endline
|
||||
| exception _ -> ())
|
||||
|> parse_and_print
|
||||
|
||||
let () = parse_and_print ()
|
21
dune-project
21
dune-project
@ -1,14 +1,27 @@
|
||||
(lang dune 2.0)
|
||||
(lang dune 3.0)
|
||||
(name nombres)
|
||||
(version 0.9)
|
||||
|
||||
(generate_opam_files true)
|
||||
|
||||
(source (github ttamttam/nombres))
|
||||
(license ISC)
|
||||
(authors "Matthieu Dubuget")
|
||||
(maintainers "matthieu.dubuget@gmail.com")
|
||||
|
||||
(package
|
||||
(name nombres)
|
||||
(name nombres)
|
||||
(synopsis "Conversion of integers to french.")
|
||||
(description
|
||||
"\| Convert ints into french.
|
||||
"\| Convert integers into french.
|
||||
"\|
|
||||
"\| Some references:
|
||||
"\| - https://leconjugueur.lefigaro.fr/frlesnombres.php
|
||||
"\| - https://www.miakinen.net/vrac/nombres
|
||||
"\| - https://www.dcode.fr/ecriture-nombre-lettres
|
||||
))
|
||||
)
|
||||
(depends
|
||||
fmt
|
||||
(qtest :with-test)
|
||||
)
|
||||
)
|
||||
|
8
lib/dune
Normal file
8
lib/dune
Normal file
@ -0,0 +1,8 @@
|
||||
(library
|
||||
(name nombres)
|
||||
(public_name nombres)
|
||||
(libraries fmt)
|
||||
(inline_tests
|
||||
(backend qtest.lib)
|
||||
(executable
|
||||
(flags :standard -warn-error -a -w -33))))
|
224
lib/nombres.ml
Normal file
224
lib/nombres.ml
Normal file
@ -0,0 +1,224 @@
|
||||
type options =
|
||||
| Septante
|
||||
| Huitante
|
||||
| Nonante
|
||||
| Belgique (* Septante Nonante *)
|
||||
| VVF (* Septante Huitante Nonante *)
|
||||
|
||||
(* let int_of_options = function *)
|
||||
(* | Septante -> 0x1 *)
|
||||
(* | Huitante -> 0x2 *)
|
||||
(* | Nonante -> 0x8 *)
|
||||
(* | Belgique -> 0x1 lor 0x8 *)
|
||||
(* | VVF -> 0x1 lor 0x2 lor 0x8 *)
|
||||
|
||||
(* type mode = [ `Belgique | `VVF | `France ] *)
|
||||
|
||||
(* let options_of_mode = function *)
|
||||
(* | `Belgique -> [ Belgique ] *)
|
||||
(* | `VVF -> [ VVF ] *)
|
||||
(* | `France -> [] *)
|
||||
|
||||
(* let int_of_mode m = *)
|
||||
(* m |> options_of_mode |> List.map int_of_options *)
|
||||
(* |> ListLabels.fold_left ~f:( + ) ~init:0 *)
|
||||
|
||||
(* 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 ()
|
||||
|
||||
(*$= nombre & ~printer:(fun x -> "\"" ^ x ^ "\"")
|
||||
"zéro" (nombre 0)
|
||||
"un" (nombre 1)
|
||||
"deux" (nombre 2)
|
||||
"trois" (nombre 3)
|
||||
"trente et un" (nombre 31)
|
||||
"trente-deux" (nombre 32)
|
||||
"soixante-dix" (nombre 70)
|
||||
"quatre-vingts" (nombre 80)
|
||||
"quatre-vingt-un" (nombre 81)
|
||||
"quatre-vingt-trois" (nombre 83)
|
||||
"quatre-vingt-dix" (nombre 90)
|
||||
"quatre-vingt-onze" (nombre 91)
|
||||
"cent" (nombre 100)
|
||||
"quatre cents" (nombre 400)
|
||||
"quatre cent vingt et un" (nombre 421)
|
||||
"mille" (nombre 1000)
|
||||
"mille cent" (nombre 1100)
|
||||
"mille deux cents" (nombre 1200)
|
||||
"mille deux cent trente" (nombre (-1230))
|
||||
"mille deux cent trente" (nombre 1230)
|
||||
"quatre-vingt mille" (nombre 80_000)
|
||||
"deux cent mille" (nombre 200_000)
|
||||
"deux cent mille trois cent quarante" (nombre 200_340)
|
||||
"quatre-vingts millions" (nombre 80_000_000)
|
||||
"quatre-vingts millions un" (nombre 80_000_001)
|
||||
"deux cents millions" (nombre 200_000_000)
|
||||
"deux cents millions trois cent quarante" (nombre 200_000_340)
|
||||
"deux cents milliards" (nombre 200_000_000_000)
|
||||
"deux cents billiards" (nombre 200_000_000_000_000_000)
|
||||
"deux trillions" (nombre 2_000_000_000_000_000_000)
|
||||
"deux trillions un" (nombre 2_000_000_000_000_000_001)
|
||||
"deux trillions quatre cent mille un" (nombre 2_000_000_000_000_400_001)
|
||||
"deux trillions quatre cents millions un" (nombre 2_000_000_000_400_000_001)
|
||||
"deux trillions cent billions quatre cents millions un" (nombre 2_000_100_000_400_000_001)
|
||||
*)
|
8
lib/nombres.mli
Normal file
8
lib/nombres.mli
Normal file
@ -0,0 +1,8 @@
|
||||
type options =
|
||||
| Septante
|
||||
| Huitante
|
||||
| Nonante
|
||||
| Belgique (* Septante Nonante *)
|
||||
| VVF (* Septante Huitante Nonante *)
|
||||
|
||||
val nombre : ?options:options list -> int -> string
|
56
nombres.ml
56
nombres.ml
@ -1,56 +0,0 @@
|
||||
let rec nombre_of_int = function
|
||||
| 0 -> "zéro"
|
||||
| 1 -> "un"
|
||||
| 2 -> "deux"
|
||||
| 3 -> "trois"
|
||||
| 4 -> "quatre"
|
||||
| 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 dizaine = nombre_of_int (n / 10 * 10) in
|
||||
let unite = n mod 10 in
|
||||
[ dizaine; nombre_of_int unite ]
|
||||
|> String.concat (if unite = 1 then " et " else "-")
|
||||
|
||||
and jusqua_100 dizaine n =
|
||||
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 centaine = n / 100 and reste = n mod 100 in
|
||||
let cent = if centaine > 1 && reste = 0 then "cents" else "cent" in
|
||||
( (if centaine = 1 then [ cent ] else [ nombre_of_int centaine; cent ])
|
||||
@ if reste = 0 then [] else [ nombre_of_int reste ] )
|
||||
|> String.concat " "
|
||||
|
||||
and jusqua_1000000 n =
|
||||
let milliers = n / 1000 and reste = n mod 1000 in
|
||||
( (if milliers = 1 then [ "mille" ] else [ nombre_of_int milliers; "mille" ])
|
||||
@ if reste = 0 then [] else [ nombre_of_int reste ] )
|
||||
|> String.concat " "
|
38
nombres.opam
Normal file
38
nombres.opam
Normal file
@ -0,0 +1,38 @@
|
||||
# This file is generated by dune, edit dune-project instead
|
||||
opam-version: "2.0"
|
||||
version: "0.9"
|
||||
synopsis: "Conversion of integers to french."
|
||||
description: """
|
||||
Convert integers into french.
|
||||
|
||||
Some references:
|
||||
- https://leconjugueur.lefigaro.fr/frlesnombres.php
|
||||
- https://www.miakinen.net/vrac/nombres
|
||||
- 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: [
|
||||
"dune" {>= "3.0"}
|
||||
"fmt"
|
||||
"qtest" {with-test}
|
||||
"odoc" {with-doc}
|
||||
]
|
||||
build: [
|
||||
["dune" "subst"] {dev}
|
||||
[
|
||||
"dune"
|
||||
"build"
|
||||
"-p"
|
||||
name
|
||||
"-j"
|
||||
jobs
|
||||
"@install"
|
||||
"@runtest" {with-test}
|
||||
"@doc" {with-doc}
|
||||
]
|
||||
]
|
||||
dev-repo: "git+https://github.com/ttamttam/nombres.git"
|
93
notes.org
Normal file
93
notes.org
Normal file
@ -0,0 +1,93 @@
|
||||
* Simples
|
||||
≤ 16
|
||||
10, 20, 30, 40, 50, 60
|
||||
100
|
||||
1000
|
||||
* trait union
|
||||
< 100 : "-"
|
||||
Mais ceux qui se terminent par 1 : " et "
|
||||
SAUF 81 et 91
|
||||
|
||||
* rectif 1990
|
||||
'-' de partout, sauf millier, millions, milliard
|
||||
|
||||
* cent
|
||||
invariable sauf si multiplié et final
|
||||
|
||||
200 000 deux cent mille
|
||||
200 000 000 deux cents millions
|
||||
|
||||
(car mille = cardinal, mais millions = nom)
|
||||
|
||||
80 000 quatre-vingt mille
|
||||
80 000 000 quatre-vingts millions
|
||||
|
||||
* Échelle longue/courte
|
||||
|
||||
Depuis 1961 : échelle longue en France
|
||||
|
||||
Échelle longue :
|
||||
- million (6)
|
||||
- milliard (9)
|
||||
- billion (12)
|
||||
- billiard (15)
|
||||
- trillion (18)
|
||||
- trilliard (21)
|
||||
|
||||
Échelle courte :
|
||||
- million (6 = 3×2)
|
||||
- billion (9 = 3×3)
|
||||
- trillion (12 = 3×4)
|
||||
- quadrillion (15 = 3×5)
|
||||
- quintillion (18 = 3×6)
|
||||
- sextillion (21 = 3×7)
|
||||
|
||||
* 70 80 90
|
||||
|
||||
Belgique + Suisse : septante et nonante
|
||||
Suisse Romande (cantons de Vaud, du Valais et de Frubourg) : huitante
|
||||
|
||||
* Accords
|
||||
|
||||
20 et 100 s’accordent s’ils sont multipliés sans être suivis par un autre
|
||||
nombre
|
||||
|
||||
- quatre-vingts
|
||||
- quatre-vingt-trois
|
||||
- quatre cents
|
||||
- quatre cent vingt et un
|
||||
- mille cent
|
||||
- mille deux cents
|
||||
- mille deux cent trente
|
||||
- deux cent mille
|
||||
- deux cents millions
|
||||
- deux cents milliards
|
||||
- quatre-vingt mille
|
||||
- quatre-vingts millions
|
||||
|
||||
1000 : « mille » est invariable
|
||||
|
||||
« un » est invariable en nombre (mais pas en genre)
|
||||
|
||||
million et milliard sont des noms et non des adjectifs. Ils
|
||||
s’accordent.
|
||||
|
||||
- quatre cents millions
|
||||
- deux cent mille
|
||||
|
||||
* Options
|
||||
|
||||
- rectif_1990 :
|
||||
Seuls les noms tels que millier, million ou milliard ne sont
|
||||
ni précédés ni suivis d'un trait d'union.
|
||||
- vingt-et-un
|
||||
- cent-soixante-huit
|
||||
- cent-mille-deux-cent-cinquante-huit
|
||||
- deux millions huit-cents
|
||||
|
||||
- septante, huitante, octante, nonante
|
||||
- belgique = septante | nonante : Belgique, Suisse romande
|
||||
- vvf = septante|huitante|nonante : Cantons de Vaud, Valais Fribourg
|
||||
- archaique = septante| octante | nonante : Plus employé
|
||||
|
||||
|
Reference in New Issue
Block a user