Ta mère elle référence des string ruby devant la piscine de Maubeuge
Sous ce titre primesautier se dissimule un problème idiot rencontré hier soir sur le développement de Typo que j’aurais certainement résolu plus rapidement sans un abus de mojitos.
Je voulais modifier la manière dont Typo transforme les URL en liens permanents en supprimant les caractères spéciaux et accentués. J’ai donc fait le bout de code suivant :
def stripped_title
str = self.title
accents = { ['á','à','â','ä','ã','Ã','Ä','Â','À'] => 'a',
['é','è','ê','ë','Ë','É','È','Ê'] => 'e',
['í','ì','î','ï','I','Î','Ì'] => 'i',
['ó','ò','ô','ö','õ','Õ','Ö','Ô','Ò'] => 'o',
['œ'] => 'oe',
['ß'] => 'ss',
['ú','ù','û','ü','U','Û','Ù'] => 'u',
['ç','Ç'] => 'c'
}
accents.each do |ac,rep|
ac.each do |s|
str.gsub!(s, rep)
end
end
str.gsub(/<[^>]*>/,'').to_url
endÀ priori, ça semble correct. Malheureusement, une fois la fonction exécutée, les accents ont été retirés et de str, ce qui est normal, et de self.title, ce qui l’est moins. Une autre manifestation du double effet kiss cool diront certains, mais surtout un oubli manifeste de la nature profondément objet de Ruby.
Que s’est-il passé ?
Lorsque j’ai déclaré str = self.title, je n’ai pas copié le contenu de la chaîne dans la variable str, mais j’ai fait pointer str vers self.title. Résultat, toute modification de la première entraînait obligatoirement la modification de la seconde. Pour avoir le résultat escompté j’aurais du déclarer str = String.new(self.title). Ça m’a rappelé le C et mes premiers exercices avec les pointeurs. Souvenirs.
Le code correct est donc :
def stripped_title
str = String.new(self.title)
accents = { ['á','à','â','ä','ã','Ã','Ä','Â','À'] => 'a',
['é','è','ê','ë','Ë','É','È','Ê'] => 'e',
['í','ì','î','ï','I','Î','Ì'] => 'i',
['ó','ò','ô','ö','õ','Õ','Ö','Ô','Ò'] => 'o',
['œ'] => 'oe',
['ß'] => 'ss',
['ú','ù','û','ü','U','Û','Ù'] => 'u',
['ç','Ç'] => 'c'
}
accents.each do |ac,rep|
ac.each do |s|
str.gsub!(s, rep)
end
end
str.gsub(/<[^>]*>/,'').to_url
end
Commentaires
Trackbacks
Les trackbacks sont fermés pour cause de spam.
Passionné d'informatique depuis l'âge de six ans, je travaille en tant que responsable qualité chez blueKiwi Software, éditeur spécialiste des outils collaboratifs en entreprise. Ma double formation en sciences politiques et en informatique me permet de porter un regard particulier sur les problématiques abordées par mon poste.
Eric about 3 hours later:
Il y a plus simple : l’utilisation d’iconv
Tu convertis de ton codage classique vers US-ASCII avec l’option //TRANSLIT
Ca te fera sauter tous tes accents et tes caractères non ascii, avec pile ce qu’il faut.
Comme ça tu n’oublieras pas les majuscules accentuées, les cédilles, les tilda, etc.
FlorentG about 4 hours later:
En Java c’est pareil. Ou pour tout langage où les Strings sont des objets passés par référence.
@Eric : j’ai fait pareil. C’est, je pense, la meilleure solution.
Je fais d’abord une conversion utf-8 vers utf-8 avec //IGNORE pour nettoyer la string de tout caractère invalide/chelou. Puis vers US-ASCII en //TRANSLIT. Ensuite je convertis tout en minuscule, je remplace certains signes de ponctuation par des tirets. Et voilà :)
Strass about 7 hours later:
Je m’oppose formellement à l’utilisation d’iconv ! En effet, ça part d’un bon sentiment : un code clean de quelques lignes qui fait bien le boulot. Sauf qu’entre une Ubuntu Gutsy et mon serveur sous Debian Etch (quand même pas la mer à boire), ça ne donne pas du tout le même résultat ! Il y a sans doute une solution super géniale et sans doute très bête à ce comportement, mais avec l’utilisation d’une table de conversion comme le fait Frédéric, on est sur d’arriver au résultat escompté.
Olivier Bonnaure about 13 hours later:
Pour ce probl�me de pointeur, j’utilise toujours la fonction clone de Object. On aurait du donc pu faire aussi : str = self.title.clone
FlorentG about 13 hours later:
@Strass : ouais c’est sûr, ça peut varier, maintenant dans mon cas précis, j’ai que deux environnement à gaffer : win32 et un linux. Aussi, ne pas oublier de définire la locale (du moins sous PHP), un setlocale(‘fr_fr’) permet déjà d’avoir un comportement assez similaire d’une machine à l’autre.
pouype about 13 hours later:
AAahh, on va avoir des corrections totomatique des url dans le prochain typo !!! :D coool
Sinon attention, en java les strings on un comportement particulier, pas forcement très objets :p
Eric about 21 hours later:
@Strass:
Moi je m’oppose formellement à toute interprétation qui ne contient pas le é majuscule, le à, ou le ç majuscule. Je les utilise régulièrement quand je fais de l’écrit “réfléchi”. Comme il m’arrive de parler italien j’attend aussi les ì, ò et ù. J’impose aussi les lettres composés (e dans le o par exemple)
Le problème c’est que je ne fais pas confiance à grand monde pour ce qui est de penser à toutes les combinaisons (même en se limitant à l’europe de l’ouest). Dans une conversion en liste noire, on est sûr d’en oublier. Des gens ont très bien fait le boulot dans une bibliothèque intégrée par défaut, ça serait du gachi de ne pas l’utiliser. (et je ne parle même pas des problèmes de perf sur des gsub multiples)
Moe 1 day later:
Et Œ ? Et les autres caractères $ , : . & # ! ? * ©, comment sont-ils traités ?
Strass 4 days later:
@Eric
En fait, j’étais partie sur la transformation iconv, j’étais très fier du code : en lignes tout était fait. Mais en déployant en prod, j’ai remarqué que le comportement était un poil différent… J’en suis donc arrivé à la solution de la table de hache… Faudra que je me repenche sur le problème.