Manipulation de nom de fichier en TinyScheme sous Gimp

Menu principal

Scheme ne manipule pas aisément les chaînes de caractères. Sous Gimp, cela ne pose généralement pas de problèmes car la majorité des scripts travaille directement sur une image.

Mais quand on veut travailler sur des fichiers, il faut bien gérer leurs noms et leurs extensions.

Voici quelques fonctions de manipulation de nom de fichier.

Les fonctions

Le code source ci-après définit 3 fonctions :

Ces 3 fonctions sont présentées ensemble car extension et remplace-extension utilise sans-extension pour leurs traitements.

sans-extension

La fonction sans-extension prend un nom de fichier en entrée (nom-fichier) et le retourne après lui avoir ôté son extension, s’il en a une.

Son fonctionnement est proche de la fonction basename d’autres langages à la différence près que sans-extension ne touche aucunement au chemin du fichier. Elle retire uniquement l’extension.

Ex. :

scheme
(sans-extension "/home/utilisateur/fichier.jpeg") → "/home/utilisateur/fichier"

extension

La fonction extension fait l’inverse de sans-extension : elle retourne uniquement l’extension du fichier avec son point.

Si le fichier n’a pas d’extension, une chaîne vide est retournée.

Ex. :

scheme
(extension "fichier.jpeg") → ".jpeg"

remplace-extension

La fonction remplace-extension change l’extension d’un fichier pour une autre.

Si le fichier n’a pas d’extension, la nouvelle extension est simplement ajoutée.

Cette fonction est utile sous Gimp si vous faites du traitement par lot de fichiers et que vous les convertissiez dans un autre format.

Ex. :

scheme
(remplace-extension "fichier.jpeg" ".tiff") → "fichier.tiff"

Le code source

scheme
; Retourne un nom de fichier sans son extension
(define (sans-extension nom-fichier)
  (let loop ((nom nom-fichier))
    (cond
      ; Si le nom est vide, il n’y a pas d’extension, on retourne le nom complet
      ((string=? nom "") nom-fichier)

      ; Si le dernier caractère est un slash, il n’y a pas d’extension
      ((char=? (string-ref nom (- (string-length nom) 1)) #\/)
        ; on retourne le nom complet
        nom-fichier
      )

      ; Si le dernier caractère est un point
      ((char=? (string-ref nom (- (string-length nom) 1)) #\.)
        ; on retourne le nom en lui enlevant le dernier caractère
        (substring nom 0 (- (string-length nom) 1))
      )

      ; Sinon on supprime le dernier caractère du nom et on boucle
      (else (loop (substring nom 0 (- (string-length nom) 1))))
    )
  )
)

; Retourne l’extension d’un nom de fichier
(define (extension nom-fichier)
  ; Extension=nom de fichier - nom de fichier sans extension
  (substring nom-fichier (string-length (sans-extension nom-fichier)))
)

; Remplace l’extension d’un fichier par une autre
(define (remplace-extension nom-fichier nouvelle-extension)
  (string-append (sans-extension nom-fichier) nouvelle-extension)
)

Fonctionnement

Une boucle particulière

Le fonctionnement des fonctions extension et remplace-extension est trivial, je ne m’attarderai donc pas dessus.

La fonction sans-extension est, quant à elle, plus tordue.

Son principe est de partir de la fin du nom de fichier et de remonter jusqu’à tomber sur un point indiquant le début de l’extension. Sur ce principe, une fonction récursive aurait très bien pu faire l’affaire.

Mais c’était sans compter sur les cas tordus !

Par cas tordus, j’entends :

Dans ces deux cas, la fonction doit retourner la chaîne telle qu’elle. Ce n’est pas possible avec une fonction récursive qui aura perdu le nom complet en cours de route. Enfin si, c’est possible, mais il faudrait ajouter un deuxième paramètre invariable tout au long des appels récursifs mais l’utilisation de la fonction en serait devenu compliquée.

La fonction sans-extension parcourt donc le nom de fichier de la fin au début au moyen d’une boucle.

Et cette boucle est particulière pour qui est habitué aux langages itératifs ou objets.

Vous connaissez probablement la fonction let* qui permet de créer un bloc d’exécution avec un ensemble de variables locales.

Voici sa petite sœur let, sans l’astérisque ! (je dis “petite sœur” mais on peut voir let* comme une simplification de let)

La fonction let permet aussi de créer un bloc d’exécution avec un ensemble de variables locales. Mais on peut donner un nom à cet ensemble. Dans la fonction sans-extension je l’ai appelée loop (boucle en anglais) pour faciliter la compréhension.

Pour faire un nouveau tour, il suffit d’appeler loop avec les nouvelles valeurs voulues.

Encore de la récursivité ! Et, cette fois, sans utiliser de fonction !

Je vous l’accorde, ce n’est plus de la gymnastique intellectuelle… Celui ou celle qui nous a pondu ça devait pas être très net ;-)

Les cas possibles

Il y a 4 cas possibles que la fonction gère pour chaque caractère pris à rebours :