202 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\b\text;
 | |
| 
 | |
| use nur\b\ValueException;
 | |
| use nur\txt;
 | |
| 
 | |
| /**
 | |
|  * Class Word: accord d'un nom ou d'un adjectif en genre et en nombre
 | |
|  *
 | |
|  * Pour accorder un nom, construire l'objet avec une spécification de la forme
 | |
|  * "ARTICLE NOM|GENRE"
 | |
|  * - L'article peut être "l'", "le", "la". Le genre est requis avec "l'"
 | |
|  * - Le genre peut être "|masculin" ou "|feminin"
 | |
|  * - Le nom est composé d'un ou plusieurs mots qui se terminent par
 | |
|  *   - #s pour un pluriel en "s", e.g porte#s
 | |
|  *   - #x pour un pluriel en "x", e.g lieu#x
 | |
|  *   - rien si le mot est invariable
 | |
|  *
 | |
|  * Pour accorder un adjectif, la spécification peut se limiter à "ADJECTIF"
 | |
|  * - L'adjectif est composé d'un ou plusieurs mots, qui en plus des marques du
 | |
|  *   pluriel peuvent se terminent par
 | |
|  *   - #e pour indiquer la marque du féminin, e.g "né#e"
 | |
|  *   - rien si le mot est invariable
 | |
|  *
 | |
|  * Chaque mot peut aussi commencer par "^" pour indiquer les caractères qui
 | |
|  * peuvent être mis en majuscule par la méthode u(). Par défaut, seule la
 | |
|  * première lettre est mise en majuscule
 | |
|  */
 | |
| class Word {
 | |
|   /** @var bool le mot est-il féminin? */
 | |
|   private $fem;
 | |
|   /** @var string article "le", "la", "l'" */
 | |
|   private $le;
 | |
|   /** @var string article "du", "de la", "de l'" */
 | |
|   private $du;
 | |
|   /** @var string article "au", "à la", "à l'" */
 | |
|   private $au;
 | |
|   /** @var string le mot sans article */
 | |
|   private $w;
 | |
| 
 | |
|   function __construct(string $spec, bool $adjective=false) {
 | |
|     if (preg_match('/\s*\|f(?:[eé]m(?:inin)?)?\s*$/iu', $spec, $ms, PREG_OFFSET_CAPTURE)) {
 | |
|       $fem = true;
 | |
|       $spec = substr($spec, 0, $ms[0][1]);
 | |
|     } elseif (preg_match('/\s*\|m(?:asc(?:ulin)?)?\s*$/i', $spec, $ms, PREG_OFFSET_CAPTURE)) {
 | |
|       $fem = false;
 | |
|       $spec = substr($spec, 0, $ms[0][1]);
 | |
|     } else {
 | |
|       $fem = null;
 | |
|     }
 | |
|     if (preg_match('/^l\'\s*/i', $spec, $ms) && $fem !== null) {
 | |
|       $le = "l'";
 | |
|       $du = "de l'";
 | |
|       $au = "à l'";
 | |
|       $spec = substr($spec, strlen($ms[0]));
 | |
|     } elseif (preg_match('/^la\s+/i', $spec, $ms)) {
 | |
|       $fem = true;
 | |
|       $le = "la ";
 | |
|       $du = "de la ";
 | |
|       $au = "à la ";
 | |
|       $spec = substr($spec, strlen($ms[0]));
 | |
|     } elseif (preg_match('/^le\s+/i', $spec, $ms)) {
 | |
|       $fem = false;
 | |
|       $le = "le ";
 | |
|       $du = "du ";
 | |
|       $au = "au ";
 | |
|       $spec = substr($spec, strlen($ms[0]));
 | |
|     } else {
 | |
|       $le = null;
 | |
|       $du = null;
 | |
|       $au = null;
 | |
|     }
 | |
|     if (!$adjective) {
 | |
|       # si c'est un nom, il faut l'article et le genre
 | |
|       if ($fem === null) {
 | |
|         throw new ValueException("Vous devez spécifier le genre du nom");
 | |
|       } elseif ($le === null || $du === null || $au === null) {
 | |
|         throw new ValueException("Vous devez spécifier l'article du nom");
 | |
|       }
 | |
|     }
 | |
|     $this->fem = $fem;
 | |
|     $this->le = $le;
 | |
|     $this->du = $du;
 | |
|     $this->au = $au;
 | |
|     $this->w = $spec;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * retourner le mot sans article
 | |
|    *
 | |
|    * @param bool|int $amount nombre du nom, avec l'équivalence false===0 et
 | |
|    * true===2. à partir de 2, le mot est ecrit au pluriel
 | |
|    * @param bool|string $fem genre du nom avec lequel accorder les adjectifs,
 | |
|    * avec l'équivalence false==="M" et true==="F"
 | |
|    */
 | |
|   function w($amount=1, bool $upper1=false, $fem=false): string {
 | |
|     if ($amount === true) $amount = 2;
 | |
|     elseif ($amount === false) $amount = 0;
 | |
|     $amount = abs($amount);
 | |
|     $w = $this->w;
 | |
|     # marque du nombre
 | |
|     if ($amount <= 1) {
 | |
|       $w = preg_replace('/#[sx]/', "", $w);
 | |
|     } else {
 | |
|       $w = preg_replace('/#([sx])/', "$1", $w);
 | |
|     }
 | |
|     # marque du genre
 | |
|     if ($fem === "f" || $fem === "F") $fem = true;
 | |
|     elseif ($fem === "m" || $fem === "M") $fem = false;
 | |
|     $repl = $fem? "$1": "";
 | |
|     $w = preg_replace('/#([e])/', $repl, $w);
 | |
|     # mise en majuscule
 | |
|     if ($upper1) {
 | |
|       if (strpos($w, "^") === false) {
 | |
|         # uniquement la première lettre
 | |
|         $w = txt::upper1($w);
 | |
|       } else {
 | |
|         # toutes les lettres qui suivent les occurences de ^
 | |
|         $w = preg_replace_callback('/\^([[:alpha:]])/u', function ($ms) {
 | |
|           return mb_strtoupper($ms[1]);
 | |
|         }, $w);
 | |
|       }
 | |
|     }
 | |
|     return $w;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * retourner le mot sans article avec la première lettre en majuscule.
 | |
|    * alias pour $this->w($amount, true, $fem)
 | |
|    *
 | |
|    * @param bool|int $amount
 | |
|    */
 | |
|   function u($amount=1, $fem=false): string {
 | |
|     return $this->w($amount, true, $fem);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * retourner l'adjectif accordé avec le genre spécifié.
 | |
|    * alias pour $this->w($amount, false, $fem)
 | |
|    *
 | |
|    * @param bool|int $amount
 | |
|    */
 | |
|   function a($fem=false, $amount=1): string {
 | |
|     return $this->w($amount, false, $fem);
 | |
|   }
 | |
| 
 | |
|   /** retourner le mot sans article et avec la quantité */
 | |
|   function q(int $amount=1, $fem=false): string {
 | |
|     return $amount." ".$this->w($amount, $fem);
 | |
|   }
 | |
| 
 | |
|   /** retourner le mot avec l'article indéfini et la quantité */
 | |
|   function un(int $amount=1, $fem=false): string {
 | |
|     $abs_amount = abs($amount);
 | |
|     if ($abs_amount == 0) {
 | |
|       $aucun = $this->fem? "aucune ": "aucun ";
 | |
|       return $aucun.$this->w($amount, $fem);
 | |
|     } elseif ($abs_amount == 1) {
 | |
|       $un = $this->fem? "une ": "un ";
 | |
|       return $un.$this->w($amount, $fem);
 | |
|     } else {
 | |
|       return "les $amount ".$this->w($amount, $fem);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function le(int $amount=1, $fem=false): string {
 | |
|     $abs_amount = abs($amount);
 | |
|     if ($abs_amount == 0) {
 | |
|       $le = $this->fem? "la 0 ": "le 0 ";
 | |
|       return $le.$this->w($amount, $fem);
 | |
|     } elseif ($abs_amount == 1) {
 | |
|       return $this->le.$this->w($amount, $fem);
 | |
|     } else {
 | |
|       return "les $amount ".$this->w($amount, $fem);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function du(int $amount=1, $fem=false): string {
 | |
|     $abs_amount = abs($amount);
 | |
|     if ($abs_amount == 0) {
 | |
|       $du = $this->fem? "de la 0 ": "du 0 ";
 | |
|       return $du.$this->w($amount, $fem);
 | |
|     } elseif ($abs_amount == 1) {
 | |
|       return $this->du.$this->w($amount, $fem);
 | |
|     } else {
 | |
|       return "des $amount ".$this->w($amount, $fem);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function au(int $amount=1, $fem=false): string {
 | |
|     $abs_amount = abs($amount);
 | |
|     if ($abs_amount == 0) {
 | |
|       $au = $this->fem? "à la 0 ": "au 0 ";
 | |
|       return $au.$this->w($amount, $fem);
 | |
|     } elseif ($abs_amount == 1) {
 | |
|       return $this->au.$this->w($amount, $fem);
 | |
|     } else {
 | |
|       return "aux $amount ".$this->w($amount, $fem);
 | |
|     }
 | |
|   }
 | |
| }
 |