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

Sur la tour Eiffel

Publié le 04 octobre 2007 à 19h56 Publié sous

Mots clés ror, coding, ruby, code, rubyonrails, rails

Si cet article vous a plu, n'hésitez pas à me suivre sur Twitter.

  1. Avatar

    Par Eric le 04 octobre 2007 à 22h38 :


    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.

  2. Avatar

    Par FlorentG le 04 octobre 2007 à 23h34 :


    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à :)

  3. Avatar

    Par Strass le 05 octobre 2007 à 03h13 :


    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é.

  4. Avatar

    Par Olivier Bonnaure le 05 octobre 2007 à 09h04 :


    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

  5. Avatar

    Par FlorentG le 05 octobre 2007 à 09h10 :


    @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.

  6. Avatar

    Par pouype le 05 octobre 2007 à 09h24 :


    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

  7. Avatar

    Par Eric le 05 octobre 2007 à 16h44 :


    @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)

  8. Avatar

    Par Moe le 05 octobre 2007 à 23h55 :


    Et Œ ? Et les autres caractères $ , : . & # ! ? * ©, comment sont-ils traités ?

  9. Avatar

    Par Strass le 09 octobre 2007 à 12h21 :


    @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.

  10. Avatar

    Par Thibaut Barrère le 30 janvier 2009 à 23h25 :


    Iconv peut effectivement échouer selon les plateformes…

    La lib diacritics_fu (github.com/thbar/diacritics_fu/tree) ou la méthode parameterize (dans Rails récent) peuvent gérer la suppression des diacritiques de façon portable.

Réagir à Ta mère elle référence des string ruby devant la piscine de Maubeuge

Merci de vous exprimer dans un français correct. Les commentaires déplacés, injurieux et le spam seront supprimés.

Les trackbacks sont fermés pour cause de spam.


Abonnez-vous au flux RSS et suivez les nouveaux articles du site Suivez-moi sur Twitter