Quels sales caractères !

Résolu/Fermé
heliconius Messages postés 545 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 - 16 mai 2020 à 00:44
heliconius Messages postés 545 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 - 16 mai 2020 à 17:28
Bonjour,

Je n'ai pas mauvais caractère mais j'ai un problème de caractères (ISO-8859-1 vs UTF-8).

Je rentre dans une table des noms d'auteurs (exemple --en minuscules-- molière). Comme je ne sais pas comment la saisie sera faite, je voudrais normaliser l'écriture des noms et prénoms : nom tout en majuscules, prénoms en minuscules avec capitale(s).

La fonction ucfirst() pourrait presque faire l'affaire si le prénom était simple (ex: jean => Jean) mais ne conviendrait pas pour jean-pierre => Jean-pierre. Je me suis fait une fonction qui met des initiales à chaque prénom simple ou composé, avec espace ou trait-d'union. Mais quand je pense à éliane (et non à Fernande :) Je tique pour la capitale accentuée mais c'est rare. Et si le problème que je pose pour le nom trouve une solution, ce sera réglé pour le prénom aussi.

Si l'on saisit comme nom : molière ou Molière dans un champ :
 <input type="text" name="nom">

en utilisant strtoupper(), str_replace(), ou strtr() je n'arrive pas à obtenir MOLIERE.

Voici les solutions essayées :
<?php
if($_POST["submit"]) {
	echo "<pre>";
	$ok  = "aaaeeeeiioouuuc";
	$ko  = "àâäéèêëîïôöùûüç";
	$ko1 = array('à ','â','ä','é','è','ê','ë','î','ï','ô','ö','ù','û','ü','ç');
	$ko2 = array('à','â','ä','é','è','ê','ë','î','ï','ô','ö','ù','û','ü','ç');
	$ok1 = array('a','a','a','e','e','e','e','i','i','o','o','u','u','u','c');
	$rep = array('à ' =>'a','â' =>'a','ä' =>'a','é' =>'e','è' =>'e','ê' =>'e','ë' =>'e','î' =>'i','ï' =>'i','ô' =>'o','ö' =>'o','ù' =>'u','û' =>'u','ü' =>'u','ç' =>'c');
	echo "0a. ".$ok."  longueur: ".strlen($ok)."\n";
	echo "0b. ".$ko."  longueur: ".strlen($ko)."\n";
	echo "0c. "; print_r($ko1); echo "\n";
	echo "0d. "; print_r($ko2); echo "\n";
	echo "-----\n";
	echo "1. ".strtoupper($_POST["nom"])."\n";
	echo "-----\n";
	echo "2. ".strtoupper(str_replace($ko, $ok, $_POST["nom"]))."\n";
	echo "3. ".strtoupper(str_replace($ko1, $ok1, $_POST["nom"]))."\n";
	echo "-----\n";
	echo "4. ".strtoupper(strtr($_POST["nom"], $ko, $ok))."\n";
	echo "5. ".strtoupper(strtr($_POST["nom"], $rep))."\n";
	echo "-----\n";
	echo "6. ".strtoupper(utf8_decode($_POST["nom"]))."\n";
	echo "-----\n";
	echo "7. ".strtoupper(str_replace($ko, $ok, utf8_decode($_POST["nom"])))."\n";
	echo "8. ".strtoupper(strtr(utf8_decode($_POST["nom"]), $ko, $ok))."\n";
	echo "-----\n";
	echo "9. ".strtoupper(str_replace(utf8_decode($ko), $ok, $_POST["nom"]))."\n";
	echo "-----\n";
	echo "</pre>";
	die();
}
?><!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>MAJ</title>
</head>

<body>
  <form method="post" name="getnom" action="getnom.php">
    nom : <input type="text" name="nom">
    <input type="submit" name="submit" value="Saisir">
  </form>
</body>

</html>


Et voici les résultats obtenus :
0a. aaaeeeeiioouuuc
0b. à âäéèêëîïôöùûüç
0c. Array
(
[0] => Ã
[1] => â
[2] => ä
[3] => é
[4] => è
[5] => ê
[6] => ë
[7] => î
[8] => ï
[9] => ô
[10] => ö
[11] => ù
[12] => û
[13] => ü
[14] => ç
)

0d. Array
(
[0] => Ã
[1] => â
[2] => ä
[3] => é
[4] => è
[5] => ê
[6] => ë
[7] => î
[8] => ï
[9] => ô
[10] => ö
[11] => ù
[12] => û
[13] => ü
[14] => ç
)

-----
1. MOLIèRE
-----
2. MOLIèRE
3. MOLIèRE
-----
4. MOLICORE
5. MOLIèRE
-----
6. MOLIèRE
-----
7. MOLIèRE
8. MOLIèRE
-----
9. MOLIèRE
-----


Mais jamais de MOLIERE !

Quelqu'un a-t-il déjà rencontré ce problème et a-t-il trouvé une solution ?
Merci pour votre aide.


Configuration: Windows / Firefox 52.0

1 réponse

jordane45 Messages postés 38169 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 8 mai 2024 4 660
16 mai 2020 à 01:46
1
heliconius Messages postés 545 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 137
16 mai 2020 à 17:28
Re-bonjour,

Merci beaucoup mais cette page, quoique intéressante, ne fournit pas la solution du problème. De même qu'en grammaire il faut respecter la concordance des temps, cette page explique la nécessité de respecter la concordance d'encodage entre l'éditeur, la BDD et l'affichage dans le navigateur pour que l'accentuation soit correctement respectée. Mais elle apporte un éclairage évident sur la manière de travailler ainsi que d'autres informations utiles mais n'explique pas la "majusculisation" avec PHP (je n'osais pas dire la capitalisation, ça fait un peu trop financier).

Le problème avec PHP et ses fonctions
strtoupper()
,
str_replace()
et
strtr()
est qu'il travaille caractère par caractère (octet par octet) et que dans
strtr()
par exemple, il remplace chaque caractère de "àâäéèêëîïôöùûüç" par le caractère ayant la même position dans "aaaeeeeiioouuuc". De ce fait, avec l'encodage ANSI
strtr("molière","àâäéèêëîïôöùûüç","aaaeeeeiioouuuc");

fonctionne très bien et "molière" devient "moliere" qu'on peut ensuite mettre en majuscules :
echo strtoupper(strtr("molière","àâäéèêëîïôöùûüç","aaaeeeeiioouuuc"));

fonctionnera très bien en ANSI et molière en minuscules s'écrira MOLIERE en majuscules.

Sauf que... pour gagner en nombre de caractères possibles, UTF-8 code sur 1 octet un caractère ASCII et sur 2 octets (2 caractères) nos caractères diacritiques (accentués et cédilles) De ce fait, le "
é
" devient "
é
" et il faudrait pouvoir travailler non plus caractère par caractère mais caractère par double-caractère. Alors forcément, quelle que soit l'ordre d'imbrication dans le cumul des fonctions
str_replace()
,
strtr()
,
strtoupper()
, le résultat était voué à l'échec.

J'ai trouvé deux solutions. La première en PHP, la seconde en javascript.

J'ai constaté qu'en cas de nos caractère diacritique --je ne parle pas des caractères vietnamiens ou chinois-- (donc sur 2 octets, 2 caractères), le premier est toujours '
Ã
'. La fonction qui résout mon problème est, dans une boucle, de vérifier la chaîne, caractère après caractère. Si c'est un caractère ANSI (1 octet), il est ajouté à une chaîne initialement vide, si c'est le caractère '
Ã
', (signalant un caractère UTF-8 sur 2 octets) on vérifie le suivant --ex: '
©
'-- pour ajouter à la chaîne la lettre correspondante non accentuée. Et cela fonctionne très bien. molière "majusculé" devient MOLIERE. Voici le code qui remplit son office :
<?php
function newstrtoupper($string) {
	$lg = strlen($string);
	$chaine = "";
	for($n=0; $n<$lg; $n++) {
		if($string[$n] == "Ã") {
			$n++;
			switch($string[$n]) {
				case ' ': $chaine .= 'a'; break;
				case '¢': $chaine .= 'a'; break;
				case '¤': $chaine .= 'a'; break;
				case '©': $chaine .= 'e'; break;
				case '¨': $chaine .= 'e'; break;
				case 'ª': $chaine .= 'e'; break;
				case '«': $chaine .= 'e'; break;
				case '®': $chaine .= 'i'; break;
				case '¯': $chaine .= 'i'; break;
				case '´': $chaine .= 'o'; break;
				case '¶': $chaine .= 'o'; break;
				case '¹': $chaine .= 'u'; break;
				case '»': $chaine .= 'u'; break;
				case '¼': $chaine .= 'u'; break;
				case '§': $chaine .= 'c'; break;
			} }
		else {
			$chaine .= $string[$n];
		}
	}
	return strtoupper($chaine);
}
if($_POST["submit"]) {
	echo "<pre>";
	$nom = strtoupper($_POST["nom"]);
	$newnom = newstrtoupper($_POST["nom"]);
	echo "strtoupper()    : $nom - ".strlen($nom)." caractères\n";
	echo "newstrtoupper() : $newnom - ".strlen($newnom)." caractères\n";
	echo "</pre>";
	die();
}
?><!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>MAJ</title>
</head>

<body>
  <form method="post" name="getnom" action="<?php echo $_SERVER["PHP_SELF"]; ?>">
    nom : <input type="text" name="nom">
    <input type="submit" name="submit" value="Saisir">
  </form>
</body>

</html>


Mais attention ! Ce code ne fonctionne que s'il est écrit avec un éditeur ANSI ou encodé en ANSI (Notepad++ : Encodage/Encoder en ANSI) car s'il est écrit avec un éditeur UTF-8, le caractère de comparaison du
if($string[$n] == "Ã")
sera écrit, lui aussi en UTF-8. Du coup la comparaison échouera, le remplacement ne se fera pas et l'on réobtiendra MOLIèRE à la place de MOLIERE.

La seconde solution ne réside donc pas dans PHP mais côté client avec du javascript. Lors de la soumission du formulaire une function verif() est exécutée et la valeur du champ saisi est remplacée par sa conversion en majuscules [
nom.toUpperCase()
]. Dans ce cas on obtiendra des majuscules accentuées (molière => MOLIÈRE) et on ne mettra pas ce champ en majuscules lorsqu'il arrivera dans PHP. Ou seconde solution --que j'ai adoptée-- je remplace les lettres accentuées par ces mêmes lettres non accentuées (molière => moliere). Dans ce cas, utilisation de
strtoupper()
côté PHP (moliere => MOLIERE). Voici le code javascript :
<?php
if($_POST["submit"]) {
	echo "<pre>";
	echo strtoupper($_POST["nom"]);
	echo "</pre>";
	die();
}
?><!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>MAJ</title>
<script language="javascript" type="text/javascript">
function noaccent(chaine) {
	var accentsA = new RegExp('[àäâ]', 'gi');
	var accentsE = new RegExp('[éèëê]', 'gi');
	var accentsI = new RegExp('[ïîì]', 'gi');
	var accentsO = new RegExp('[öôò]', 'gi');
	var accentsU = new RegExp('[üûù]', 'gi');
	var accentsY = new RegExp('[ÿ]', 'gi');
	var accentsC = new RegExp('[ç]', 'gi');

	chaine = chaine.replace(accentsA, 'a');
	chaine = chaine.replace(accentsE, 'e');
	chaine = chaine.replace(accentsI, 'i');
	chaine = chaine.replace(accentsO, 'o');
	chaine = chaine.replace(accentsU, 'u');
	chaine = chaine.replace(accentsY, 'y');
	chaine = chaine.replace(accentsC, 'c');
	return chaine;
}
function verif() {
	// var nom = document.getnom.nom.value;
	// var nom1 = nom.toUpperCase(); // Avec majuscules accentuées. Ne pas utiliser strtoupper() PHP
	// alert(nom1); // Pour voir
	// var nom2 = noaccent(nom); // Avec minuscules non accentuées
	// alert(nom2.toUpperCase()); // Pour voir en majuscules
	// document.getnom.nom.value = nom2; // attribution de la valeur
	document.getnom.nom.value = noaccent(document.getnom.nom.value);
	return true;
}
</script>
</head>

<body>
  <form method="post" name="getnom" action="<?php echo $_SERVER["PHP_SELF"]; ?>" onsubmit="return verif();">
    nom : <input type="text" name="nom">
    <input type="submit" name="submit" value="Saisir">
  </form>
</body>

</html>


Voilà. C'est un peu long mais si ça peut servir... UTF-8, malgré les apports indéniables pour la diversité des caractères que ça apporte est malgré tout un vrai casse-tête.

En tout cas, le lien proposé était utile et j'y ai appris qu'on pouvait préciser lors de la connexion à la BDD le charset qui sera utilisé. Finalement, je ne suis pas mécontent qu'on m'ait fortement conseillé d'utiliser PDO.. ;-) Plus de possibilités et plus de polyvalences par rapport aux types de BDD.

Merci et à plus tard...
Problème résolu.
0