Salut à tous,
ça fait un petit moment que je bute sur un problème qui m'avait semblé simple au départ mais que j'ai l'impression d'avoir sous-estimé.
Contexte
J'appends le c++ depuis un peu plus d'un an. Pour ca j'ai entrepris d'écrire une application dans le cadre de mon travail pour analyser des données venant d'un détecteur. Le logiciel fonctionne et il est utilisé par mes collègues dans le cadre du développement de notre projet.
Pour améliorer mes connaissances j'ai aussi entrepris de réécrire mes scripts (python, bash, perl) en c++. C'est peut être pas malin mais ça me fait un exercice…
Le premier que j'ai souhaité réécrire c'est un petit script qui s'appelle formatname dont l'objectif est de mettre les noms de fichiers d'un dossier ou d'un seul fichier sous une forme simple qui pourrait peut être se résumer par [a-z0-9_.]*
Le problème
En fait je bloque sur la partie caractères étendus. Toutes ces lettres accentuées qui font la richesse de nos langues mais qui font mon malheur. Dans mon script bash j'avais utilisé une fonction écrite par Christophe Blaess et que je reproduis ci-dessous
#
# author Christophe Blaess
# link https://www.blaess.fr/christophe/livres/scripts-shell-linux-et-unix/
#
function latin_to_ascii {
local result
result=$(echo "$1" |
sed -e 's/[ÀÁÂÃÄÅ]/A/g' |
sed -e 's/Æ/AE/g' |
sed -e 's/Ç/C/g' |
sed -e 's/[ÈÉÊË]/E/g' |
sed -e 's/[ÌÍÎÏ]/I/g' |
sed -e 's/Ñ/N/g' |
sed -e 's/[ÒÓÔÕÖØ]/O/g' |
sed -e 's/[ÙÚÛÜ]/U/g' |
sed -e 's/Ý/Y/g' |
sed -e 's/[àáâãä]/a/g' |
sed -e 's/æ/ae/g' |
sed -e 's/ç/c/g' |
sed -e 's/[èéêë]/e/g' |
sed -e 's/[ìíîï]/i/g' |
sed -e 's/ñ/n/g' |
sed -e 's/[òóôöø]/o/g' |
sed -e 's/[ùúûü]/u/g' |
sed -e 's/ý/y/g')
echo "$result"
}
J'ai essayé de faire pareil en c++ en utilisant les expressions régulières mais sans succès. Mes premières recherches semblent montrer que c'est un problèmes d'encodage. Si j'ai bien compris les caractères accentués sont stockés sur 2 octets et ca fout le bazar pour ce type de conversion.
std::regex re;
std::cout << "input string: " << s << std::endl;
re = "[éèëěê]";
s = std::regex_replace (s, re, "e",std::regex_constants::format_default);
std::cout << "output string: " << s << std::endl;
On m'a aussi conseillé d'essayer libiconv mais j'y arrive pas non plus. Pourtant ça à l'air simple mais je dois pas être doué :)
#include <cctype>
#include <cstddef>
#include <cstring>
#include <filesystem>
#include <ios>
#include <iostream>
#include <iconv.h>
#include <filesystem>
#include <cstdio>
int main (int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; ++i)
{
char* origin = argv[i];
size_t ol = strlen (origin);
char destination[100];
size_t dl = strlen (destination);
memset(destination, 0, 100);
char * pin = origin;
char * pout = destination;
iconv_t conv = iconv_open ("ASCII", "UTF-8");
int ret = iconv(conv, &pin, &ol, &pout, &dl);
iconv_close (conv);
fprintf(stderr,"out: %s\n",destination);
std::cout << "longeur origin: " << ol << std::endl;
std::cout << "longeur destination: " << strlen(destination) << std::endl;
std::cout << "origin: " << origin << std::endl;
std::cout << "destination: " << destination << std::endl;
}
}
else
std::cout << "no argument provided" << std::endl;
return 0;
}
En tout cas, merci d'avance pour votre aide.
Olivier
# Le code ?
Posté par Anthony Jaguenaud . Évalué à 2.
Salut,
Tu devrais mettre le code tel que tu l’as écrit jusque là, on pourra peut-être t’aider à adapter, debugguer.
[^] # Re: Le code ?
Posté par Olivier LEMAIRE (site web personnel) . Évalué à 1.
oui tu as raison… Je l'ai ajouté au message original.
Merci
Les logiciels de traitement de texte sont à la rédaction ce que la 2CV est à l'automobile, une vieille voiture dont on se souvient avec nostalgie mais technologiquement dépassée
[^] # Re: Le code ?
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 2.
Du coup on voit que tu utilises libiconv pour lequel tu as un wrapper intéressant ici : https://github.com/unnonouno/iconvpp Et sinon tu peux étudier l'exemple assez complet du site officiel : https://www.gnu.org/software/libc/manual/html_node/iconv-Examples.html
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
# hop
Posté par fearan . Évalué à 7.
moi j'utiliserai un truc dédié :
boost::locale::normalize()
ça demande une dépendance à boost, mais ça prévoie plus de cas que ce que tu peux imaginer ;)
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
# Alternative déjà dispo
Posté par Julien.D . Évalué à 3. Dernière modification le 22 février 2022 à 18:02.
Bonjour,
Je ne sais pas si c'est un exercice ou si tu n'as pas trouvé ton bonheur ailleurs, mais tu peux jeter un coup d'oeil à detox, utilitaire en ligne de commande pour retirer les caractères et espaces qui peuvent poser problème dans les scripts en général ou dans les systèmes de fichiers, je l'utilise parfois sur des milliers de fichiers et ça fait le job ;)
(rien à voir, mais ton site perso est cassé :/ )
[^] # Re: Alternative déjà dispo
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 2.
C'est bien un exercice (ou alors la personne se fait plaisir dans son apprentissage de C++) …et il semble que ça fait appel à
iconv
qui bien aussi (et parfois mieux.)“It is seldom that liberty of any kind is lost all at once.” ― David Hume
# Retour d'erreur ?
Posté par Anthony Jaguenaud . Évalué à 6. Dernière modification le 22 février 2022 à 22:53.
Salut,
Tu ne teste pas les retours de tes fonctions, c’est mal.
Même chose pour iconv_open.
Rajoute la gestion des erreurs, ça t’aidera à trouver ce qui cloche.
[^] # Re: Retour d'erreur ?
Posté par Olivier LEMAIRE (site web personnel) . Évalué à 1. Dernière modification le 23 février 2022 à 09:29.
oui, tu as raison… ce n'est pas bien. En fait comme j'utilise gdb parfois j'oublie de tester ces valeurs de retour pendant la phase de mise au point… Mais ce n'est peut être pas un bon comportement et il faut probablement l'inclure tout de suite.
Les logiciels de traitement de texte sont à la rédaction ce que la 2CV est à l'automobile, une vieille voiture dont on se souvient avec nostalgie mais technologiquement dépassée
[^] # Re: Retour d'erreur ?
Posté par Anthony Jaguenaud . Évalué à 4. Dernière modification le 23 février 2022 à 10:32.
Quand j’ai testé le code chez moi hier soir, j’avais un retour d’erreur sur
iconv
. Après, c’est peut-être lié à mon terminal qui n’était peut-être pas en UTF8, mais ton programme doit toujours vérifier tous les codes de retour qui peuvent échouer.Quand je ne vérifie pas un code de retour volontairement, par exemple
printf
, je lecast
:Je sais que printf n’est pas c++, mais c’est l’exemple qui m’est venu immédiatement en tête. ;-)
[^] # Re: Retour d'erreur ?
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 3.
Il y la structure et les checks nécessaires qui sont indiqué dans l'exemple que j'avais pointé (on est un peu loin de ce qui a été fait.
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
# Erreur du débutant
Posté par gorbal . Évalué à 2. Dernière modification le 23 février 2022 à 08:29.
Il y a très peu de chance que dl contienne la taille du tableau.
Il faudrait écrire cela:
[^] # Re: Erreur du débutant
Posté par Olivier LEMAIRE (site web personnel) . Évalué à 1.
oui, c'est vrai que j'ai des problèmes avec ce point. Merci pour le tuyau !
Les logiciels de traitement de texte sont à la rédaction ce que la 2CV est à l'automobile, une vieille voiture dont on se souvient avec nostalgie mais technologiquement dépassée
# une solution ?
Posté par Olivier LEMAIRE (site web personnel) . Évalué à 3.
Bonjour à tous et merci beaucoup pour votre aide.
Ci-dessous un début de solution qui intègrent vos conseils et qui semble fonctionner.
La ligne qui change tout (pour moi) c'est std::setlocale(LC_ALL, "en_US.UTF-8");
J'ai tester en local et sur un compilo en ligne dont je vous mets le lien ici.
https://godbolt.org/z/4sW4eWjKe
Les logiciels de traitement de texte sont à la rédaction ce que la 2CV est à l'automobile, une vieille voiture dont on se souvient avec nostalgie mais technologiquement dépassée
[^] # Re: une solution ?
Posté par Anthony Jaguenaud . Évalué à 3.
Tu as oublié de traiter le cas :
[^] # Re: une solution ?
Posté par fearan . Évalué à 3.
c'est plus proche du C que du C++ ça :D
Mais bon vu que ça utilise une bibliothèque C…
ensuite
dans la boucle for? j'ai comme un doute
et toujours dans la même idée, on arrive pas à le faire; mais on fait quand même
j'ajouterai
n'a pas d'intérêt pas de copie des chaines, juste des pointeurs, on se retrouve avec 3 variables différentes qui pointent au même endroit argv[i], origin, pin…
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.