affiche et addition
This commit is contained in:
parent
73d53f33eb
commit
8020b189ae
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sophie"
|
||||||
|
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "sophie"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
18
shell.nix
Normal file
18
shell.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { overlays = [ (import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz)) ]; },}:
|
||||||
|
with pkgs;
|
||||||
|
|
||||||
|
mkShell {
|
||||||
|
nativeBuildInputs = with xorg; [
|
||||||
|
pkg-config
|
||||||
|
] ++ [
|
||||||
|
cargo
|
||||||
|
rustc
|
||||||
|
];
|
||||||
|
buildInputs = [
|
||||||
|
latest.rustChannels.stable.rust
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXtst
|
||||||
|
libevdev
|
||||||
|
];
|
||||||
|
}
|
118
src/main.rs
118
src/main.rs
|
@ -1,13 +1,119 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
mod nombres;
|
||||||
|
|
||||||
|
enum ErreurSophie {
|
||||||
|
CommandeInconnue(String),
|
||||||
|
PhraseVide,
|
||||||
|
ManqueArgument,
|
||||||
|
OrthographeNombre(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ErreurSophie {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::CommandeInconnue(commande) => write!(f, "La commande \"{}\" est inconnue.", commande),
|
||||||
|
Self::PhraseVide => write!(f, "La phrase est vide."),
|
||||||
|
Self::ManqueArgument => write!(f, "Il manque un argument."),
|
||||||
|
Self::OrthographeNombre(nombre) => write!(f, "Le nombre \"{}\" est mal orthographié.", nombre),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let arguments: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
let file_path = &args[1];
|
if arguments.len() < 2 {
|
||||||
|
eprintln!("Utilisation : sophie <FILE>");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let chemin_de_fichier = &arguments[1];
|
||||||
|
|
||||||
let contents = fs::read_to_string(file_path)
|
match fs::read_to_string(chemin_de_fichier) {
|
||||||
.expect("Should have been able to read the file");
|
Ok(contenu) => {
|
||||||
|
execute(contenu);
|
||||||
println!("content : \n{}", contents);
|
}
|
||||||
|
Err(raison) => {
|
||||||
|
eprintln!("Fichier illisible : {}", raison);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute(contenu: String) {
|
||||||
|
let contenu_propre = contenu.replace("\n", "");
|
||||||
|
let mut texte: Vec<&str> = contenu_propre.split('.').collect();
|
||||||
|
texte.pop(); // remove empty phrase after last dot
|
||||||
|
for (index_phrase, phrase) in texte.iter().enumerate() {
|
||||||
|
match execute_phrase(phrase) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(raison) => {
|
||||||
|
eprintln!("Erreur phrase {} : {}", index_phrase + 1, raison);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_phrase(phrase: &str) -> Result<(), ErreurSophie> {
|
||||||
|
let phrase = phrase.trim();
|
||||||
|
let parties: Vec<&str> = phrase.splitn(2, ' ').collect();
|
||||||
|
|
||||||
|
if parties.is_empty() {
|
||||||
|
return Err(ErreurSophie::PhraseVide)
|
||||||
|
}
|
||||||
|
|
||||||
|
if parties.len() == 1 {
|
||||||
|
return Err(ErreurSophie::ManqueArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
match parties[0] {
|
||||||
|
"Modifie" => {
|
||||||
|
modifie(parties[1])?;
|
||||||
|
},
|
||||||
|
"Affiche" => {
|
||||||
|
affiche(parties[1])?;
|
||||||
|
},
|
||||||
|
"Demande" => {
|
||||||
|
demande(parties[1])?;
|
||||||
|
}
|
||||||
|
autre_commande => {
|
||||||
|
return Err(ErreurSophie::CommandeInconnue(autre_commande.to_string()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifie(arguments: &str) -> Result<(), ErreurSophie> {
|
||||||
|
println!("- modifie : {}", arguments);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn affiche(arguments: &str) -> Result<(), ErreurSophie> {
|
||||||
|
let liste_arguments: Vec<&str> = arguments.split(',').collect();
|
||||||
|
|
||||||
|
let mut texte = "".to_string();
|
||||||
|
|
||||||
|
for argument in liste_arguments {
|
||||||
|
let argument: &str = argument.trim();
|
||||||
|
if argument.starts_with('"') {
|
||||||
|
if argument.ends_with('"') {
|
||||||
|
texte += &argument[1..argument.len()-1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let resultat = nombres::operation(argument)?;
|
||||||
|
texte += &nombres::nombre_comme_texte(resultat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{}", texte);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn demande(arguments: &str) -> Result<(), ErreurSophie> {
|
||||||
|
println!("- demande : {}", arguments);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
206
src/nombres.rs
Normal file
206
src/nombres.rs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
use super::ErreurSophie;
|
||||||
|
|
||||||
|
const NOMS_UNITES: [&str; 10] = ["", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf"];
|
||||||
|
const NOMS_UNITES_DIX: [&str; 10] = ["dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"];
|
||||||
|
const NOMS_DIZAINES: [&str; 9] = ["", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "x", "quatre-vingts"];
|
||||||
|
const NOMS_SEPARATEURS: [&str; 7] = ["", "mille", "million", "milliard", "billion", "billiard", "trillion"];
|
||||||
|
const UNION: &str = "-";
|
||||||
|
|
||||||
|
pub fn nombre_comme_texte(nombre: usize) -> String {
|
||||||
|
if nombre == 0 {
|
||||||
|
return "zéro".to_string()
|
||||||
|
}
|
||||||
|
if nombre >= 10usize.pow(18) {
|
||||||
|
return "infini".to_string()
|
||||||
|
}
|
||||||
|
let mut groupes: Vec<usize> = vec![];
|
||||||
|
let mut nombre = nombre;
|
||||||
|
while nombre > 0 {
|
||||||
|
groupes.insert(0, nombre % 1000);
|
||||||
|
nombre /= 1000;
|
||||||
|
}
|
||||||
|
let mut chaine: String = "".to_string();
|
||||||
|
|
||||||
|
for index in 0..groupes.len() {
|
||||||
|
if groupes[index] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let pluriel: &str = if (groupes.len() - index - 1 > 1) && groupes[index] > 1 {
|
||||||
|
"s"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
if index < groupes.len() - 1 {
|
||||||
|
let union = if index > 0 {UNION} else {""};
|
||||||
|
let chiffre = if groupes.len() - index - 1 == 1 && groupes[index] == 1 { // un mille
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
petit_nombre_comme_texte(groupes[index]) + UNION
|
||||||
|
};
|
||||||
|
chaine += &format!("{}{}{}{}",
|
||||||
|
union,
|
||||||
|
chiffre,
|
||||||
|
NOMS_SEPARATEURS[groupes.len() - index - 1],
|
||||||
|
pluriel,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let union = if index > 0 {UNION} else {""};
|
||||||
|
chaine += union;
|
||||||
|
chaine += &petit_nombre_comme_texte(groupes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chaine
|
||||||
|
}
|
||||||
|
|
||||||
|
fn petit_nombre_comme_texte(nombre: usize) -> String {
|
||||||
|
let nombre = nombre.clamp(0, 999);
|
||||||
|
let centaine = nombre / 100;
|
||||||
|
let dizaine = (nombre % 100) / 10;
|
||||||
|
let unité = nombre % 10;
|
||||||
|
|
||||||
|
let décalage_dizaine = if [1, 7, 9].contains(&dizaine) {1} else {0};
|
||||||
|
|
||||||
|
let centaine_texte = if centaine > 1 {
|
||||||
|
format!("{}{}cent", NOMS_UNITES[centaine], UNION)
|
||||||
|
} else if centaine > 0 {
|
||||||
|
"cent".to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let dizaine_union = if centaine > 0 && dizaine > 0 {
|
||||||
|
UNION.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let dizaine_texte = NOMS_DIZAINES[dizaine - décalage_dizaine];
|
||||||
|
|
||||||
|
let séparation = if unité == 1 && ![0, 1, 8, 9].contains(&dizaine) {UNION.to_string() + "et"} else {"".to_string()};
|
||||||
|
|
||||||
|
let unité_union = if nombre - unité > 0 && unité > 0 {
|
||||||
|
UNION.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
let unité_texte = if [1, 7, 9].contains(&dizaine) {
|
||||||
|
unité_union + NOMS_UNITES_DIX[unité]
|
||||||
|
} else {
|
||||||
|
unité_union + NOMS_UNITES[unité]
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("{}{}{}{}{}", centaine_texte, dizaine_union, dizaine_texte, séparation, unité_texte)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texte_comme_nombre(texte: &str) -> Result<usize, ErreurSophie> {
|
||||||
|
let pluriel = format!("s{}", UNION);
|
||||||
|
let mut petits_nombres_texte: Vec<&str> = vec![];
|
||||||
|
let mut texte_modifie = texte;
|
||||||
|
let mut dernier_separateur = 0;
|
||||||
|
for (index, separateur_texte) in NOMS_SEPARATEURS.iter().enumerate() {
|
||||||
|
if index == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let mille: bool = texte_modifie.starts_with("mille");
|
||||||
|
let texte_separe: Vec<&str> = texte_modifie.split(separateur_texte).collect();
|
||||||
|
if texte_separe.len() > 2 {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
if texte_separe.len() > 1 {
|
||||||
|
let petit_nombre_texte = texte_separe[1]
|
||||||
|
.trim_start_matches(&pluriel)
|
||||||
|
.trim_start_matches(UNION)
|
||||||
|
.trim_end_matches(UNION);
|
||||||
|
petits_nombres_texte.push(petit_nombre_texte);
|
||||||
|
texte_modifie = if mille {
|
||||||
|
"un"
|
||||||
|
} else {
|
||||||
|
texte_separe[0]
|
||||||
|
};
|
||||||
|
dernier_separateur = index;
|
||||||
|
} else if !petits_nombres_texte.is_empty() {
|
||||||
|
petits_nombres_texte.push("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let petit_nombre_texte = texte_modifie
|
||||||
|
.trim_start_matches(&pluriel)
|
||||||
|
.trim_start_matches(UNION)
|
||||||
|
.trim_end_matches(UNION);
|
||||||
|
petits_nombres_texte.insert(dernier_separateur, petit_nombre_texte);
|
||||||
|
|
||||||
|
let mut nombre: usize = 0;
|
||||||
|
|
||||||
|
for (index, petit_nombre_texte) in petits_nombres_texte.iter().enumerate() {
|
||||||
|
let petit_nombre = texte_comme_petit_nombre(petit_nombre_texte)?;
|
||||||
|
nombre += petit_nombre * 1000usize.pow(index as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(nombre)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn texte_comme_petit_nombre(texte: &str) -> Result<usize, ErreurSophie> {
|
||||||
|
let elements: Vec<&str> = texte.split(UNION).collect();
|
||||||
|
|
||||||
|
let mut nombre = 0;
|
||||||
|
let mut dernier_chiffre_texte = "";
|
||||||
|
|
||||||
|
for chiffre_texte in elements {
|
||||||
|
if chiffre_texte == "cent" {
|
||||||
|
if nombre == 0 {
|
||||||
|
nombre = 1;
|
||||||
|
}
|
||||||
|
if nombre >= 100 {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
nombre *= 100;
|
||||||
|
dernier_chiffre_texte = chiffre_texte;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if chiffre_texte == "vingts" {
|
||||||
|
if dernier_chiffre_texte == "quatre" {
|
||||||
|
nombre += 80 - 4;
|
||||||
|
dernier_chiffre_texte = chiffre_texte;
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(chiffre) = NOMS_UNITES.iter().position(|&s| s == chiffre_texte) {
|
||||||
|
if nombre%10 > 0 {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
nombre += chiffre;
|
||||||
|
dernier_chiffre_texte = chiffre_texte;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if let Some(chiffre) = NOMS_DIZAINES.iter().position(|&s| s == chiffre_texte) {
|
||||||
|
if nombre%100 > 0 && chiffre != 1 {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
nombre += chiffre*10;
|
||||||
|
dernier_chiffre_texte = chiffre_texte;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if let Some(chiffre) = NOMS_UNITES_DIX.iter().position(|&s| s == chiffre_texte) {
|
||||||
|
if nombre%10 > 0 {
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
nombre += 10 + chiffre;
|
||||||
|
dernier_chiffre_texte = chiffre_texte;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return Err(ErreurSophie::OrthographeNombre(texte.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(nombre)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operation(arguments: &str) -> Result<usize, ErreurSophie> {
|
||||||
|
let somme_texte: Vec<&str> = arguments.split("plus").collect();
|
||||||
|
let mut somme : usize = 0;
|
||||||
|
for element in somme_texte {
|
||||||
|
let element_propre: &str = element.trim();
|
||||||
|
somme += texte_comme_nombre(element_propre)?
|
||||||
|
}
|
||||||
|
Ok(somme)
|
||||||
|
}
|
Loading…
Reference in a new issue