Lors du comptage des caractères en JavaScript, le problème des paires de substitution (où les emoji et certains caractères CJK comptent pour 2) est assez connu. Vous avez probablement entendu des conseils du type « utilisez simplement[...str].longueur" pour le résoudre.
Cependant, lorsque j'ai implémenté un compteur de caractères pour une zone de texte sur le frontend, j'ai découvert qu'il existe d'autres causes d'inadéquation au-delà des paires de substitution. Cela s’est avéré plus profond que prévu, j’aimerais donc partager ce que j’ai appris. Il se peut que certaines choses se trompent, alors s'il vous plaît, prenez cela comme une référence plutôt que comme une vérité absolue.
J'implémentais un compteur de caractères pour un. J'utilisais déjà[...str].longueurcomme contre-mesure de paire de substitution, mais celui de Laravelmaximumla validation rejetait toujours certaines entrées.
Après enquête, j'ai trouvé le coupable : la normalisation des nouvelles lignes.
| Cause | Côté JS | Côté PHP/MySQL | Divergence |
|---|---|---|---|
| Emoji (paires de substitution) | "🎉".longueur→ 2 | mb_strlen("🎉")→ 1 | JS compte plus |
| Normalisation de nouvelle ligne | "a\nb".longueur→ 3 | Après HTTP :"a\r\nb"→ 4 | PHP compte plus |
| Mères porteuses solitaires | Dénombré | Erreur ou avertissement MySQL | Échec possible de la sauvegarde |
| Formulaire NFD (ancien macOS) | "é".longueur→ 2 | mb_strlen("é")→ 2 | Correspond, mais involontairement 2 caractères |
Les paires de substitution peuvent être gérées avec[...str].longueur, mais le problème de la nouvelle ligne n'est pas résolu par cela seul. Plus il y a de nouvelles lignes dans le texte, plus l'écart est important : par exemple, 10 nouvelles lignes signifient une différence de +10 caractères.
C'est là que je suis resté le plus coincé.
Lorsque vous soumettez le contenu d'unvia HTTP, les nouvelles lignes sont normalisées à partir de\nà\r\n.
Selon MDN, pourwrap="doux"(la valeur par défaut) :
le navigateur garantit que tous les sauts de ligne dans la valeur saisie sont une paire CR+LF
Le blog WHATWG explique également cela en détail : les nouvelles lignes sont normalisées au format CRLF lors de la soumission du formulaire, conformément aux spécifications.
// Dans le navigateur textarea.value // "a\nb\nc" → 5 caractères // Reçu par PHP $_POST['field'] // "a\r\nb\r\nc" → 7 caractèresde Laravelmaximumutilisations des règlesmb_strlen(), il vérifie donc le nombre de caractères après la normalisation. C'est pourquoi les textes comportant de nombre...
[Courte citation de 8% de l'article original]