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
|
||||
];
|
||||
}
|
116
src/main.rs
116
src/main.rs
|
@ -1,13 +1,119 @@
|
|||
use std::env;
|
||||
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() {
|
||||
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 contents = fs::read_to_string(file_path)
|
||||
.expect("Should have been able to read the file");
|
||||
let chemin_de_fichier = &arguments[1];
|
||||
|
||||
println!("content : \n{}", contents);
|
||||
match fs::read_to_string(chemin_de_fichier) {
|
||||
Ok(contenu) => {
|
||||
execute(contenu);
|
||||
}
|
||||
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