<?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); } } }