175 lines
5 KiB
PHP
175 lines
5 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Classifier\Lib\Utils;
|
||
|
|
|
||
|
|
class StringCleaner
|
||
|
|
{
|
||
|
|
/** @var string[] */
|
||
|
|
private $stopWords;
|
||
|
|
|
||
|
|
public function __construct(array $stopWords = [])
|
||
|
|
{
|
||
|
|
$this->stopWords = array_map(function (string $word) {
|
||
|
|
return trim(mb_strtolower($word, 'UTF-8'));
|
||
|
|
}, $stopWords);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getCleanChain(string $text): string
|
||
|
|
{
|
||
|
|
$text = $this->toUtf8($text);
|
||
|
|
$text = $this->handleAcronyms($text);
|
||
|
|
$text = mb_strtolower($text, 'UTF-8');
|
||
|
|
$text = $this->translitterate($text);
|
||
|
|
return $this->removeMultiSpaces($text); // "alerte mise en securite"
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Nettoie une chaîne de caractères en appliquant plusieurs étapes de transformation
|
||
|
|
*
|
||
|
|
* @param string $text
|
||
|
|
* @return string[] Tableau de mots nettoyés
|
||
|
|
*/
|
||
|
|
public function preprocessMessage(string $text): array
|
||
|
|
{
|
||
|
|
$text = $this->toUtf8($text);
|
||
|
|
$text = mb_strtolower($text, 'UTF-8');
|
||
|
|
$text = $this->handleAcronyms($text);
|
||
|
|
$text = $this->fromUtf8ToPlainText($text);
|
||
|
|
$text = $this->safelyRemoveEmptyLines($text);
|
||
|
|
$text = $this->controlCharToSpace($text);
|
||
|
|
$text = $this->translitterate($text);
|
||
|
|
$text = $this->removeMultiSpaces($text);
|
||
|
|
|
||
|
|
|
||
|
|
$words = $this->cutIntoWords($text);
|
||
|
|
$filteredWords = $this->removeStopWords($words);
|
||
|
|
|
||
|
|
return array_values($filteredWords);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function cutIntoWords(string $text): array
|
||
|
|
{
|
||
|
|
return explode(' ', $text);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function handleAcronyms(string $text): string
|
||
|
|
{
|
||
|
|
// Transforme "P O I" ou "P.O.I" en "POI"
|
||
|
|
return preg_replace('/(?<=\b\w)\s(?=\w\b)/', '', $text);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Translittération (enlève les accents proprement)
|
||
|
|
*/
|
||
|
|
private function translitterate(string $value): string
|
||
|
|
{
|
||
|
|
// *Translittération (enlève les accents proprement)
|
||
|
|
$transliterated = false;
|
||
|
|
if (class_exists('\Transliterator')) {
|
||
|
|
$transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
|
||
|
|
if ($transliterator) {
|
||
|
|
$result = $transliterator->transliterate($value);
|
||
|
|
if ($result !== false) {
|
||
|
|
$value = $result;
|
||
|
|
$transliterated = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!$transliterated && function_exists('iconv')) {
|
||
|
|
$result = iconv('UTF-8', 'ASCII//TRANSLIT', $value);
|
||
|
|
if ($result !== false) {
|
||
|
|
$value = $result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
return preg_replace('/[^\p{L}\p{N}\s]/u', '', $value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remplace les caractères de contrôle (sauf les espaces) par des espaces
|
||
|
|
*/
|
||
|
|
private function controlCharToSpace(string $value): string
|
||
|
|
{
|
||
|
|
return preg_replace('/[\x00-\x1F\x7F]+/', ' ', $value);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function removeMultiSpaces(string $value): string
|
||
|
|
{
|
||
|
|
return trim(preg_replace('/\s+/', ' ', $value));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Supprime les stop words d'un tableau de mots
|
||
|
|
* et les mots de 1 caractère ou moins
|
||
|
|
*
|
||
|
|
* @param string[] $words
|
||
|
|
*/
|
||
|
|
private function removeStopWords(array $words): array
|
||
|
|
{
|
||
|
|
return array_filter($words, function ($word) {
|
||
|
|
return !in_array($word, $this->stopWords) && mb_strlen($word) > 1;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convertit une chaîne UTF-8 en texte brut, en supprimant les balises et en décodant les entités HTML
|
||
|
|
*/
|
||
|
|
private function fromUtf8ToPlainText(string $value): string
|
||
|
|
{
|
||
|
|
// * Supprimer les balises
|
||
|
|
$output = strip_tags($value);
|
||
|
|
|
||
|
|
// * Convertir les entités html (ex: & devient &)
|
||
|
|
$output = html_entity_decode($output, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||
|
|
|
||
|
|
return $output;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Supprime les lignes vides ou ne contenant que des espaces/tabs, et normalise les sauts de ligne
|
||
|
|
*/
|
||
|
|
private function safelyRemoveEmptyLines(string $value): string
|
||
|
|
{
|
||
|
|
// * Remplace les lignes ne contenant que des espaces/tabs par une chaîne vide
|
||
|
|
$result = preg_replace('/^\s*[\r\n]+/m', '', $value);
|
||
|
|
|
||
|
|
// * Remplace les sauts de lignes avec un `\n` unique
|
||
|
|
$result = preg_replace('/\R/', "\n", $result);
|
||
|
|
|
||
|
|
return $result ?? $value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convertit intelligemment vers UTF-8
|
||
|
|
*
|
||
|
|
* @param mixed $value
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private function toUtf8($value): string
|
||
|
|
{
|
||
|
|
if ($value === null || $value === '') {
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
$str = (string)$value;
|
||
|
|
|
||
|
|
if (mb_check_encoding($str, 'UTF-8')) {
|
||
|
|
return $str;
|
||
|
|
}
|
||
|
|
|
||
|
|
// * Détection du symbole € en ISO-8859-15 (\xA4)
|
||
|
|
if (strpos($str, "\xA4") !== false) {
|
||
|
|
$converted = iconv('ISO-8859-15', 'UTF-8//IGNORE', $str);
|
||
|
|
return ($converted !== false) ? $converted : $str;
|
||
|
|
}
|
||
|
|
|
||
|
|
// * Tenter conversion de ISO-8859-1 vers UTF-8
|
||
|
|
$converted = iconv('ISO-8859-1', 'UTF-8//IGNORE', $str);
|
||
|
|
|
||
|
|
return ($converted !== false) ? $converted : $str;
|
||
|
|
}
|
||
|
|
}
|