file_name_fixer.py

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • ewaguespack@gmail.com

    #1

    file_name_fixer.py

    i put this together to fix a bunch of files with wierd names, please
    gimme feedback, i am a newbie


    #!/usr/bin/env python
    import os
    import sys
    import string
    import platform
    dir = sys.argv[1]
    noworky = sys.argv[2]
    if platform.system () == 'Linux':
    uglychars = ''.join( set(string.punc tuation+' ') - set('/_.') )
    else:
    if platform.system () == 'Windows':#this is broken because windows
    is gay with case
    uglychars = ''.join( set(string.punc tuation+' ') -
    set(':\\/_.') )
    else:
    print "wtf... what platform is this anyway?"
    underscore = '_'
    underscore = underscore * len(uglychars)
    chars = string.maketran s(uglychars, underscore)
    print "# PHASE I, DIRECTORIES"
    for path, subdirs, files in os.walk(dir, topdown=True):
    oldname = path
    newname = oldname.transla te(chars)
    newname = string.lower(ne wname)
    while string.count(ne wname, "__") > 0:
    newname = string.replace( newname,"__","_ ")
    while string.count(ne wname, "..") > 0:
    newname = string.replace( newname,"..",". ")
    if oldname != newname:
    if os.path.isfile( newname) or os.path.isdir(n ewname):
    print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
    exists\n"
    else:
    print oldname, "-->\n", newname, "\t\t\tYAY: file
    renamed\n"
    if noworky == "doit":
    os.renames(oldn ame, newname)
    print "# PHASE II, FILES"
    for path, subdirs, files in os.walk(dir, topdown=True):
    for oldname in files:
    oldname = os.path.join(pa th, oldname)
    newname = oldname.transla te(chars)
    newname = string.lower(ne wname)
    newname = string.replace( newname,".mpeg" ,".mpg")
    newname = string.replace( newname,".ram", ".rm")
    newname = string.replace( newname,".jpeg" ,".jpg")
    newname = string.replace( newname,".qt"," .mov")
    while string.count(ne wname, "__") > 0:
    newname = string.replace( newname,"__","_ ")
    while string.count(ne wname, "..") > 0:
    newname = string.replace( newname,"..",". ")
    newname = string.replace( newname,"._","_ ")
    newname = string.replace( newname,"_.",". ")
    if oldname != newname:
    if os.path.isfile( newname) or os.path.isdir(n ewname):
    print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
    exists\n"
    else:
    print oldname, "-->\n", newname, "\t\t\tYAY: file
    renamed\n"
    if noworky == "doit":
    os.renames(oldn ame, newname)

  • bruno at modulix

    #2
    Re: file_name_fixer .py

    ewaguespack@gma il.com wrote:[color=blue]
    > i put this together to fix a bunch of files with wierd names, please
    > gimme feedback, i am a newbie
    >
    >
    > #!/usr/bin/env python
    > import os
    > import sys
    > import string
    > import platform[/color]
    [color=blue]
    > dir = sys.argv[1][/color]
    attention, ça masque la fonction dir(). Utilise de préférence un autre
    identifiant
    [color=blue]
    > noworky = sys.argv[2][/color]

    Si l'utilsateur ne passe pas deux arguments, le programme va planter
    (IndexError), sans que l'utilisateur ne sache pourquoi.

    [color=blue]
    > if platform.system () == 'Linux':
    > uglychars = ''.join( set(string.punc tuation+' ') - set('/_.') )
    > else:
    > if platform.system () == 'Windows':#this is broken because windows
    > is gay with case[/color]

    utilise if/elif/else, ce sera plus simple. Ou un dictionnaire
    nom_de_platefor me -> uglychars.
    [color=blue]
    > uglychars = ''.join( set(string.punc tuation+' ') -
    > set(':\\/_.') )
    > else:
    > print "wtf... what platform is this anyway?"[/color]

    MacOS classic, MacOSX, xxxBSD, n'importe quel Unix, ou n'importe quelle
    autre plateforme supportant Python (et il y en a un paquet).
    [color=blue]
    > underscore = '_'
    > underscore = underscore * len(uglychars)
    > chars = string.maketran s(uglychars, underscore)
    > print "# PHASE I, DIRECTORIES"
    > for path, subdirs, files in os.walk(dir, topdown=True):
    > oldname = path
    > newname = oldname.transla te(chars)
    > newname = string.lower(ne wname)[/color]

    Utilise plutôt les méthodes de l'objet str, et n'hésite pas à chainer
    les appels de méthodes:
    newname = oldname.transla te(chars).lower ()
    [color=blue]
    > while string.count(ne wname, "__") > 0:
    > newname = string.replace( newname,"__","_ ")[/color]

    Pas besoin de compter le nombre d'occurrences de '__', il suffit qu'il y
    en ait au moins une:
    while '__' in newname:
    newname = newname.replace ('__', '_')

    Et tant qu'à faire, pour ce genre de traitement, une regexp serait
    peut-être plus adaptée (tester quand même point de vue perfs).
    [color=blue]
    > while string.count(ne wname, "..") > 0:
    > newname = string.replace( newname,"..",". ")[/color]

    <*n*x>
    Attention aussi aux fichiers spéciaux '.' et '..'
    </*n*x>
    [color=blue]
    > if oldname != newname:
    > if os.path.isfile( newname) or os.path.isdir(n ewname):[/color]
    if os.path.exists( newname)
    [color=blue]
    > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
    > exists\n"[/color]

    La sortie standard est pour les sorties "normales" du programme. Pour
    les messages destinés à l'utilisateur, utiliser la sortie d'erreur
    (sys.stderr)

    Prévoir également un flag -q / --quiet (et/ou son contraire un flag -v /
    --verbose) pour activer/désactiver ces messages.
    [color=blue]
    > else:
    > print oldname, "-->\n", newname, "\t\t\tYAY: file
    > renamed\n"
    > if noworky == "doit":
    > os.renames(oldn ame, newname)[/color]

    il serait peut-être bon de préciser les options possibles, non?
    BTW, la coutume pour un flag signalant qu'on veut juste une simulation
    de l'exécution est '--dry-run'
    [color=blue]
    > print "# PHASE II, FILES"[/color]

    Y a t'il une raison de faire le traitement en deux temps ?
    [color=blue]
    > for path, subdirs, files in os.walk(dir, topdown=True):
    > for oldname in files:
    > oldname = os.path.join(pa th, oldname)
    > newname = oldname.transla te(chars)
    > newname = string.lower(ne wname)[/color]

    pour accélérer la résolution des noms, il vaut mieux créer un alias
    local avant la boucle :

    path_join = os.path.join
    for path, subdirs, files in os.walk(dir, topdown=True):
    for oldname in files:
    oldname = path_join(path, oldname)

    Tu peux aussi chainer les appels:
    oldname = path_join(path, oldname).transl ate(chars).lowe r()

    Attention aussi, tu travailles maintenant sur le chemin complet (ie:
    /path/to/myfile.ext). Tu devrais peut-être d'abord traiter le nom de
    fichier, et ne rajouter le chemin qu'à la fin pour le rename().
    [color=blue]
    > newname = string.replace( newname,".mpeg" ,".mpg")
    > newname = string.replace( newname,".ram", ".rm")
    > newname = string.replace( newname,".jpeg" ,".jpg")
    > newname = string.replace( newname,".qt"," .mov")[/color]

    # TODO : rendre ça paramétrable
    ext_map = {'mpeg' : 'mpg',
    'ram' : 'rm',
    'jpeg' : 'jpg',
    'qt' : 'mov',
    # etc
    }
    name, ext = os.path.splitex t(newname)
    if ext in ext_map:
    newname = "%s.%s" % (name, ext_map[ext])

    [color=blue]
    > while string.count(ne wname, "__") > 0:
    > newname = string.replace( newname,"__","_ ")
    > while string.count(ne wname, "..") > 0:
    > newname = string.replace( newname,"..",". ")[/color]

    Tu n'a pas l'impression de répéter du code ?-)
    [color=blue]
    > newname = string.replace( newname,"._","_ ")
    > newname = string.replace( newname,"_.",". ")[/color]

    [color=blue]
    > if oldname != newname:
    > if os.path.isfile( newname) or os.path.isdir(n ewname):
    > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
    > exists\n"
    > else:
    > print oldname, "-->\n", newname, "\t\t\tYAY: file
    > renamed\n"
    > if noworky == "doit":
    > os.renames(oldn ame, newname)
    >[/color]

    Idem...


    Tel que, ce script n'est ni réutilisable, ni même maintenable
    (duplication de code...). Il faut factoriser tout le code dupliqué dans
    des fonctions 'utilitaires', mettre le code 'principal' dans une
    fonction aussi, et ajouter une fonction 'main' qui va gérer les options
    et appeler les autres fonctions.

    Il faut aussi normaliser les options et documenter le programme
    (fonctions usage() et help()). Le module optparse peut être une bonne
    solution (gère les options et génère les messages d'aide).

    Tant qu'on est dans les options, la norme est plutôt de mettre les flags
    d'abord, et les arguments (ici, le/les chemin(s) à visiter) après. Dans
    ton cas, cela permettrait de passer plusieurs chemins à traiter.
    Egalement, il pourrait être intéressant de prévoir des options
    permettant de paramétrer les "uglychars" et les extensions à remplacer,
    soit directement sur la ligne de commande :
    monprog --uglychars="._?! %*" --extensions="jpe g:jpg,qt:mov"
    soit via un fichier de config
    monprog --init=myinit.ini

    avec par exemple:
    # myinit.ini
    uglychars="./!*$"
    extensions="jpe g:jpg,qt:mov"

    Tu peux aussi prévoir des règles précisant des chemins à ne pas toucher
    (sous-répertoire entier, noms de fichiers correspondants à un motif
    etc), s'il faut descendre dans les sous-répertoires ou non etc...

    Ca va, j'ai pas tapé trop fort ?-)

    HTH
    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in 'onurb@xiludom. gro'.split('@')])"

    Comment

    • bruno at modulix

      #3
      Re: file_name_fixer .py

      ewaguespack@gma il.com wrote:[color=blue]
      > i put this together to fix a bunch of files with wierd names, please
      > gimme feedback, i am a newbie[/color]

      Ok, so let's go... Hope you won't hate me too much !-)
      [color=blue]
      >
      > #!/usr/bin/env python
      > import os
      > import sys
      > import string
      > import platform
      > dir = sys.argv[1][/color]
      This will shadow the builtin 'dir' function.
      [color=blue]
      > noworky = sys.argv[2][/color]

      If the user fails to provide args, the program will crash with an
      IndexError - which may not be very helpful.

      Also, a better scheme would be
      myprog [-opt1 [-opt2=val [-optN]]] arg1 arg2 argN

      Hint: the optparse module is your friend

      [color=blue]
      > if platform.system () == 'Linux':
      > uglychars = ''.join( set(string.punc tuation+' ') - set('/_.') )
      > else:
      > if platform.system () == 'Windows':#this is broken because windows
      > is gay with case
      > uglychars = ''.join( set(string.punc tuation+' ') -
      > set(':\\/_.') )
      > else:
      > print "wtf... what platform is this anyway?"[/color]

      May be MacOS Classic, MacOS X or any *n*x or *BSD variant, or any other
      platform supporting Python - are there are some...
      [color=blue]
      > underscore = '_'
      > underscore = underscore * len(uglychars)[/color]

      You don't need the intermediate value:
      underscores = '_' * len(uglychars)
      [color=blue]
      > chars = string.maketran s(uglychars, underscore)[/color]
      [color=blue]
      > print "# PHASE I, DIRECTORIES"[/color]

      Why not processing dirs and files in one pass ?
      [color=blue]
      > for path, subdirs, files in os.walk(dir, topdown=True):[/color]

      Err... is the 'dir' argument supposed to be an absolute path or a
      relative path ?

      And why using the topdown option ?
      [color=blue]
      > oldname = path[/color]

      woops ! this may be the absolute path. Are you sure you want to process
      an absolute path ?

      I think you'd better process files and dirs in one path, walking bottom
      up (so you don't process any file twice).
      [color=blue]
      > newname = oldname.transla te(chars)
      > newname = string.lower(ne wname)[/color]

      Use the 'str' object methods instead of functions from the string module:

      newname = newname.lower()

      You can also chain method/function calls:
      newname = oldname.transla te(chars).lower ()

      [color=blue]
      > while string.count(ne wname, "__") > 0:[/color]

      in the context of a boolean expression, 0 evaluate to False, non-zero to
      True. So you don't have to be so explicit:
      while newname.count(' __'):
      [color=blue]
      > newname = string.replace( newname,"__","_ ")[/color]

      You don't need to actually *count* the occurrences of '__' - if there's
      one, that's enough:
      while '__' in newname:
      # proceed

      Also, a regexp may be more effective here.
      [color=blue]
      > while string.count(ne wname, "..") > 0:
      > newname = string.replace( newname,"..",". ")[/color]

      Don't forget the '..' and '.' special directories in unix filesystems...
      [color=blue]
      > if oldname != newname:
      > if os.path.isfile( newname) or os.path.isdir(n ewname):[/color]

      And if there's a special file (device etc) ?
      hint : os.path.exists( )

      [color=blue]
      > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
      > exists\n"[/color]

      stdout is for 'normal' program outputs (ie: outputs that may be used as
      inputs to another program). This kind of output should go to stderr:
      print >> sys.stdout, "%s --> %s : \t\t\tERROR: "
      "file/dir exists" % (oldname,
      newname,)
      [color=blue]
      > else:
      > print oldname, "-->\n", newname, "\t\t\tYAY: file
      > renamed\n"
      > if noworky == "doit":
      > os.renames(oldn ame, newname)[/color]

      How is the user supposed to know that he has to pass the string "doit"
      as a second arg ?

      There are some (more or less agreed upon) conventions about cli options.
      Like '--dry-run' to express the fact that the program shouldn't actually
      do more than simulate it's execution.
      [color=blue]
      > print "# PHASE II, FILES"
      > for path, subdirs, files in os.walk(dir, topdown=True):
      > for oldname in files:
      > oldname = os.path.join(pa th, oldname)[/color]

      Are you *sure* you want to operate on the *whole* *absolute* path ?
      (cf my thoughts about the "first phase" and the whole algorithm)
      [color=blue]
      > newname = oldname.transla te(chars)
      > newname = string.lower(ne wname)[/color]

      Aren't you repeating some code here ?
      hint : all duplicated code should be factored out into a function.
      [color=blue]
      > newname = string.replace( newname,".mpeg" ,".mpg")
      > newname = string.replace( newname,".ram", ".rm")
      > newname = string.replace( newname,".jpeg" ,".jpg")
      > newname = string.replace( newname,".qt"," .mov")[/color]

      # outside the loop, define a dict like:
      ext_map = {'mpeg': 'mpg',
      'ram' : 'rm',
      'jpeg' : 'jpg',
      # etc
      }

      # then in the loop:
      base, ext = os.path.split(n ewname)
      if ext in ext_map:
      newname = "%s.%s" % (base, ext_map[ext])

      [color=blue]
      > while string.count(ne wname, "__") > 0:
      > newname = string.replace( newname,"__","_ ")[/color]

      duplicated code...
      [color=blue]
      > while string.count(ne wname, "..") > 0:
      > newname = string.replace( newname,"..",". ")
      > newname = string.replace( newname,"._","_ ")
      > newname = string.replace( newname,"_.",". ")[/color]

      all this is a perfect usecase for regexps...
      [color=blue]
      > if oldname != newname:
      > if os.path.isfile( newname) or os.path.isdir(n ewname):
      > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
      > exists\n"
      > else:
      > print oldname, "-->\n", newname, "\t\t\tYAY: file
      > renamed\n"
      > if noworky == "doit":
      > os.renames(oldn ame, newname)[/color]

      duplicated code.


      Still alive ?-)

      I thing the first step would be to correct your algorithm, then use some
      more efficient or idiomatic constructs where possible (like using dicts
      instead of repeated tests, sending messages to stderr etc).

      Then here are some more hints:

      - put the processing algorithm in a dedicated function, if possible one
      that doesn't rely on any global variable,
      - factor out any duplicated code into helper functions

      - then add a 'main' function that take cares of options and call the
      'processing' function if everything's ok. The main function should
      return 0 if ok, non-zero if errors (usually 2 for invalid cli options or
      args, 1 for other errors)

      - and finally add this at the end of your module:

      if __name__ == '__main__':
      sys.exit(main(s ys.argv))


      This will allow your script to be used either as a program or as a module.


      --
      bruno desthuilliers
      python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
      p in 'onurb@xiludom. gro'.split('@')])"

      Comment

      • mdelliot@gmail.com

        #4
        Re: file_name_fixer .py

        ewaguespack@gma il.com wrote:[color=blue]
        > i put this together to fix a bunch of files with wierd names, please
        > gimme feedback, i am a newbie[/color]

        See http://aspn.activestate.com/ASPN/Coo.../Recipe/442517

        Comment

        • eww

          #5
          Re: file_name_fixer .py

          thanks for the feedback!

          I'll work on your suggestions.


          bruno at modulix wrote:[color=blue]
          > ewaguespack@gma il.com wrote:[color=green]
          > > i put this together to fix a bunch of files with wierd names, please
          > > gimme feedback, i am a newbie[/color]
          >
          > Ok, so let's go... Hope you won't hate me too much !-)
          >[color=green]
          > >
          > > #!/usr/bin/env python
          > > import os
          > > import sys
          > > import string
          > > import platform
          > > dir = sys.argv[1][/color]
          > This will shadow the builtin 'dir' function.
          >[color=green]
          > > noworky = sys.argv[2][/color]
          >
          > If the user fails to provide args, the program will crash with an
          > IndexError - which may not be very helpful.
          >
          > Also, a better scheme would be
          > myprog [-opt1 [-opt2=val [-optN]]] arg1 arg2 argN
          >
          > Hint: the optparse module is your friend
          > http://www.python.org/doc/2.4.2/lib/...-optparse.html
          >[color=green]
          > > if platform.system () == 'Linux':
          > > uglychars = ''.join( set(string.punc tuation+' ') - set('/_.') )
          > > else:
          > > if platform.system () == 'Windows':#this is broken because windows
          > > is gay with case
          > > uglychars = ''.join( set(string.punc tuation+' ') -
          > > set(':\\/_.') )
          > > else:
          > > print "wtf... what platform is this anyway?"[/color]
          >
          > May be MacOS Classic, MacOS X or any *n*x or *BSD variant, or any other
          > platform supporting Python - are there are some...
          >[color=green]
          > > underscore = '_'
          > > underscore = underscore * len(uglychars)[/color]
          >
          > You don't need the intermediate value:
          > underscores = '_' * len(uglychars)
          >[color=green]
          > > chars = string.maketran s(uglychars, underscore)[/color]
          >[color=green]
          > > print "# PHASE I, DIRECTORIES"[/color]
          >
          > Why not processing dirs and files in one pass ?
          >[color=green]
          > > for path, subdirs, files in os.walk(dir, topdown=True):[/color]
          >
          > Err... is the 'dir' argument supposed to be an absolute path or a
          > relative path ?
          >
          > And why using the topdown option ?
          >[color=green]
          > > oldname = path[/color]
          >
          > woops ! this may be the absolute path. Are you sure you want to process
          > an absolute path ?
          >
          > I think you'd better process files and dirs in one path, walking bottom
          > up (so you don't process any file twice).
          >[color=green]
          > > newname = oldname.transla te(chars)
          > > newname = string.lower(ne wname)[/color]
          >
          > Use the 'str' object methods instead of functions from the string module:
          >
          > newname = newname.lower()
          >
          > You can also chain method/function calls:
          > newname = oldname.transla te(chars).lower ()
          >
          >[color=green]
          > > while string.count(ne wname, "__") > 0:[/color]
          >
          > in the context of a boolean expression, 0 evaluate to False, non-zero to
          > True. So you don't have to be so explicit:
          > while newname.count(' __'):
          >[color=green]
          > > newname = string.replace( newname,"__","_ ")[/color]
          >
          > You don't need to actually *count* the occurrences of '__' - if there's
          > one, that's enough:
          > while '__' in newname:
          > # proceed
          >
          > Also, a regexp may be more effective here.
          >[color=green]
          > > while string.count(ne wname, "..") > 0:
          > > newname = string.replace( newname,"..",". ")[/color]
          >
          > Don't forget the '..' and '.' special directories in unix filesystems...
          >[color=green]
          > > if oldname != newname:
          > > if os.path.isfile( newname) or os.path.isdir(n ewname):[/color]
          >
          > And if there's a special file (device etc) ?
          > hint : os.path.exists( )
          >
          >[color=green]
          > > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
          > > exists\n"[/color]
          >
          > stdout is for 'normal' program outputs (ie: outputs that may be used as
          > inputs to another program). This kind of output should go to stderr:
          > print >> sys.stdout, "%s --> %s : \t\t\tERROR: "
          > "file/dir exists" % (oldname,
          > newname,)
          >[color=green]
          > > else:
          > > print oldname, "-->\n", newname, "\t\t\tYAY: file
          > > renamed\n"
          > > if noworky == "doit":
          > > os.renames(oldn ame, newname)[/color]
          >
          > How is the user supposed to know that he has to pass the string "doit"
          > as a second arg ?
          >
          > There are some (more or less agreed upon) conventions about cli options.
          > Like '--dry-run' to express the fact that the program shouldn't actually
          > do more than simulate it's execution.
          >[color=green]
          > > print "# PHASE II, FILES"
          > > for path, subdirs, files in os.walk(dir, topdown=True):
          > > for oldname in files:
          > > oldname = os.path.join(pa th, oldname)[/color]
          >
          > Are you *sure* you want to operate on the *whole* *absolute* path ?
          > (cf my thoughts about the "first phase" and the whole algorithm)
          >[color=green]
          > > newname = oldname.transla te(chars)
          > > newname = string.lower(ne wname)[/color]
          >
          > Aren't you repeating some code here ?
          > hint : all duplicated code should be factored out into a function.
          >[color=green]
          > > newname = string.replace( newname,".mpeg" ,".mpg")
          > > newname = string.replace( newname,".ram", ".rm")
          > > newname = string.replace( newname,".jpeg" ,".jpg")
          > > newname = string.replace( newname,".qt"," .mov")[/color]
          >
          > # outside the loop, define a dict like:
          > ext_map = {'mpeg': 'mpg',
          > 'ram' : 'rm',
          > 'jpeg' : 'jpg',
          > # etc
          > }
          >
          > # then in the loop:
          > base, ext = os.path.split(n ewname)
          > if ext in ext_map:
          > newname = "%s.%s" % (base, ext_map[ext])
          >
          >[color=green]
          > > while string.count(ne wname, "__") > 0:
          > > newname = string.replace( newname,"__","_ ")[/color]
          >
          > duplicated code...
          >[color=green]
          > > while string.count(ne wname, "..") > 0:
          > > newname = string.replace( newname,"..",". ")
          > > newname = string.replace( newname,"._","_ ")
          > > newname = string.replace( newname,"_.",". ")[/color]
          >
          > all this is a perfect usecase for regexps...
          >[color=green]
          > > if oldname != newname:
          > > if os.path.isfile( newname) or os.path.isdir(n ewname):
          > > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
          > > exists\n"
          > > else:
          > > print oldname, "-->\n", newname, "\t\t\tYAY: file
          > > renamed\n"
          > > if noworky == "doit":
          > > os.renames(oldn ame, newname)[/color]
          >
          > duplicated code.
          >
          >
          > Still alive ?-)
          >
          > I thing the first step would be to correct your algorithm, then use some
          > more efficient or idiomatic constructs where possible (like using dicts
          > instead of repeated tests, sending messages to stderr etc).
          >
          > Then here are some more hints:
          >
          > - put the processing algorithm in a dedicated function, if possible one
          > that doesn't rely on any global variable,
          > - factor out any duplicated code into helper functions
          >
          > - then add a 'main' function that take cares of options and call the
          > 'processing' function if everything's ok. The main function should
          > return 0 if ok, non-zero if errors (usually 2 for invalid cli options or
          > args, 1 for other errors)
          >
          > - and finally add this at the end of your module:
          >
          > if __name__ == '__main__':
          > sys.exit(main(s ys.argv))
          >
          >
          > This will allow your script to be used either as a program or as a module.
          >
          >
          > --
          > bruno desthuilliers
          > python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
          > p in 'onurb@xiludom. gro'.split('@')])"[/color]

          Comment

          • Bruno Desthuilliers

            #6
            Re: file_name_fixer .py

            eww a écrit :
            (top-post corrected)[color=blue]
            > bruno at modulix wrote:
            >[color=green]
            >>ewaguespack@g mail.com wrote:
            >>[color=darkred]
            >>>i put this together to fix a bunch of files with wierd names, please
            >>>gimme feedback, i am a newbie[/color]
            >>
            >>Ok, so let's go... Hope you won't hate me too much !-)[/color][/color]

            (snip program and comments)
            [color=blue]
            > thanks for the feedback![/color]

            You're welcome. Feel free to ask for more details here if you're unsure
            about some particular point of it.
            [color=blue]
            > I'll work on your suggestions.[/color]

            <ot>
            So while you're at it, please follow this one too: avoid posting back
            the whole post you're answering to. Keep the relevant parts only and put
            your answers where appropriate... Readability is important - and not
            only in source code !-)
            </ot>

            --
            bruno at modulix

            Comment

            • Steven D'Aprano

              #7
              Re: file_name_fixer .py

              ewaguespack@gma il.com wrote:
              [color=blue]
              > i put this together to fix a bunch of files with wierd names, please
              > gimme feedback, i am a newbie[/color]

              Others have already made comments, here is some more
              food for thought.

              You should consider factoring out some repeated code
              into functions. E.g.:

              # warning: untested!!!
              def replace_all(s, old, new):
              """Replaces all instances of substring old with
              substring new."""
              if old == new:
              # make no changes
              return s
              elif old in new:
              raise ValueError("old substring can't be "
              "part of the replacement substring.")
              while old in s:
              s = s.replace(old, new)
              return s

              Now you can call it in your loop:
              [color=blue]
              > for path, subdirs, files in os.walk(dir, topdown=True):
              > oldname = path
              > newname = oldname.transla te(chars)
              > newname = string.lower(ne wname)[/color]
              [color=blue]
              > while string.count(ne wname, "__") > 0:
              > newname = string.replace( newname,"__","_ ")
              > while string.count(ne wname, "..") > 0:
              > newname = string.replace( newname,"..",". ")[/color]

              becomes:

              newname = replace_all(new name, "__", "_")
              newname = replace_all(new name, "..", ".")
              [color=blue]
              > if oldname != newname:
              > if os.path.isfile( newname) or os.path.isdir(n ewname):
              > print oldname, "-->\n", newname, "\t\t\tERRO R: file/dir
              > exists\n"
              > else:
              > print oldname, "-->\n", newname, "\t\t\tYAY: file
              > renamed\n"
              > if noworky == "doit":
              > os.renames(oldn ame, newname)
              > print "# PHASE II, FILES"
              > for path, subdirs, files in os.walk(dir, topdown=True):
              > for oldname in files:
              > oldname = os.path.join(pa th, oldname)
              > newname = oldname.transla te(chars)
              > newname = string.lower(ne wname)[/color]

              More refactoring:
              [color=blue]
              > newname = string.replace( newname,".mpeg" ,".mpg")
              > newname = string.replace( newname,".ram", ".rm")
              > newname = string.replace( newname,".jpeg" ,".jpg")
              > newname = string.replace( newname,".qt"," .mov")[/color]

              becomes:

              # warning: untested!!!
              def fix_extension(s , old, new):
              # there are other, better ways of doing this
              # see the os.path.splitex t function
              if s.endswith(old) :
              s = s[:-len(old)] + new
              return s

              def fix_all_extensi ons(s, extensions):
              for old, new in extensions:
              s = fix_extension(s , old, new)
              return s


              newname = fix_all_extensi ons(newname,
              [ (".mpeg", ".mpg"), (".ram", ".rm"),
              (".jpeg", ".jpg"), (".qt", ".mov") ]

              [color=blue]
              > while string.count(ne wname, "__") > 0:
              > newname = string.replace( newname,"__","_ ")
              > while string.count(ne wname, "..") > 0:
              > newname = string.replace( newname,"..",". ")[/color]

              We've already refactored those calls:

              newname = replace_all(new name, "__", "_")
              newname = replace_all(new name, "..", ".")



              That will do for starters.


              --
              Steven.

              Comment

              • Fredrik Lundh

                #8
                Re: file_name_fixer .py

                Steven D'Aprano wrote:
                [color=blue]
                > You should consider factoring out some repeated code
                > into functions. E.g.:
                >
                > # warning: untested!!!
                > def replace_all(s, old, new):
                > """Replaces all instances of substring old with
                > substring new."""
                > if old == new:
                > # make no changes
                > return s
                > elif old in new:
                > raise ValueError("old substring can't be "
                > "part of the replacement substring.")
                > while old in s:
                > s = s.replace(old, new)
                > return s
                >
                > Now you can call it in your loop:
                >[color=green]
                > > for path, subdirs, files in os.walk(dir, topdown=True):
                > > oldname = path
                > > newname = oldname.transla te(chars)
                > > newname = string.lower(ne wname)[/color]
                >[color=green]
                > > while string.count(ne wname, "__") > 0:
                > > newname = string.replace( newname,"__","_ ")
                > > while string.count(ne wname, "..") > 0:
                > > newname = string.replace( newname,"..",". ")[/color]
                >
                > becomes:
                >
                > newname = replace_all(new name, "__", "_")
                > newname = replace_all(new name, "..", ".")[/color]

                or you can use a more well-suited function:

                # replace runs of _ and . with a single character
                newname = re.sub("_+", "_", newname)
                newname = re.sub("\.+", ".", newname)

                or, slightly more obscure:

                newname = re.sub("([_.])\\1+", "\\1", newname)

                </F>



                Comment

                • Steven D'Aprano

                  #9
                  Re: file_name_fixer .py

                  Fredrik Lundh wrote:
                  [color=blue]
                  > or you can use a more well-suited function:
                  >
                  > # replace runs of _ and . with a single character
                  > newname = re.sub("_+", "_", newname)
                  > newname = re.sub("\.+", ".", newname)[/color]

                  You know, I really must sit down and learn how to use
                  reg exes one of these days. But somehow, every time I
                  try, I get the feeling that the work required to learn
                  to use them effectively is infinitely greater than the
                  work required to re-invent the wheel every time.

                  *wink*
                  [color=blue]
                  > or, slightly more obscure:
                  >
                  > newname = re.sub("([_.])\\1+", "\\1", newname)[/color]

                  _Slightly_?


                  --
                  Steven.

                  Comment

                  • Fredrik Lundh

                    #10
                    Re: file_name_fixer .py

                    Steven D'Aprano wrote:
                    [color=blue][color=green]
                    > > or you can use a more well-suited function:
                    > >
                    > > # replace runs of _ and . with a single character
                    > > newname = re.sub("_+", "_", newname)
                    > > newname = re.sub("\.+", ".", newname)[/color]
                    >
                    > You know, I really must sit down and learn how to use
                    > reg exes one of these days. But somehow, every time I
                    > try, I get the feeling that the work required to learn
                    > to use them effectively is infinitely greater than the
                    > work required to re-invent the wheel every time.[/color]

                    here's all you need to understand the code above:

                    . ^ $ * + ? ( ) [] { } | \ are reserved characters
                    all other characters match themselves
                    reserved characters must be escaped to match themselves;
                    to match a dot, use \. (which the RE engine sees as \.)
                    + means match one or more of the preceeding item
                    so _+ matches one or more underscores, and \.+ matches
                    one or more dots
                    re.sub(pattern, replacement, text) replaces all matches for
                    the given pattern in text with the given replacement string

                    so re.sub("_+", "_", newname) replaces runs of underscores with
                    a single underscore.
                    [color=blue][color=green]
                    > > or, slightly more obscure:
                    > >
                    > > newname = re.sub("([_.])\\1+", "\\1", newname)[/color]
                    >
                    > _Slightly_?[/color]

                    this introduces three new concepts:

                    [ ] defines a set of characters
                    so [_.] will match either _ or .
                    ( ) defines a group of matched characters.
                    \\1 (which the RE engine sees as \1) refers to the first group
                    this can be used both in the pattern and in the replacement
                    string

                    so re.sub("([_.])\\1+", "\\1", newname) replaces runs consisting
                    of either a . or an _ followed by one or more copies of itself, with
                    a single instance of itself.

                    (using r-strings lets you remove some of extra backslashes, btw)

                    </F>



                    Comment

                    • Richie Hindle

                      #11
                      Re: file_name_fixer .py


                      [Fredrik][color=blue]
                      > so re.sub("([_.])\\1+", "\\1", newname) replaces runs consisting
                      > of either a . or an _ followed by one or more copies of itself, with
                      > a single instance of itself.[/color]

                      ....and this:
                      [color=blue][color=green][color=darkred]
                      >>> def isprime(n):
                      >>> return n > 1 and not re.match(r'(xx+ )\1+$', 'x'*n)[/color][/color][/color]

                      finds prime numbers.

                      I'll get me coat.

                      --
                      Richie Hindle
                      richie@entrian. com

                      Comment

                      • Thomas Heller

                        #12
                        Re: file_name_fixer .py

                        Richie Hindle <richie@entrian .com> writes:
                        [color=blue]
                        > [Fredrik][color=green]
                        >> so re.sub("([_.])\\1+", "\\1", newname) replaces runs consisting
                        >> of either a . or an _ followed by one or more copies of itself, with
                        >> a single instance of itself.[/color]
                        >
                        > ...and this:
                        >[color=green][color=darkred]
                        >>>> def isprime(n):
                        >>>> return n > 1 and not re.match(r'(xx+ )\1+$', 'x'*n)[/color][/color]
                        >
                        > finds prime numbers.[/color]

                        So, who will post a 'Pior' (Python in one regex)?

                        Thomas

                        Comment

                        • Steven D'Aprano

                          #13
                          Re: file_name_fixer .py

                          On Wed, 25 Jan 2006 10:37:12 +0000, Richie Hindle wrote:
                          [color=blue]
                          >
                          > [Fredrik][color=green]
                          >> so re.sub("([_.])\\1+", "\\1", newname) replaces runs consisting
                          >> of either a . or an _ followed by one or more copies of itself, with
                          >> a single instance of itself.[/color]
                          >
                          > ...and this:
                          >[color=green][color=darkred]
                          >>>> def isprime(n):
                          >>>> return n > 1 and not re.match(r'(xx+ )\1+$', 'x'*n)[/color][/color]
                          >
                          > finds prime numbers.
                          >
                          > I'll get me coat.[/color]


                          See, now that's exactly the sort of thing that makes me wake screaming
                          in the night. That's just deeply, deeply wrong -- I don't know what's
                          worse, that it *works*, or that somebody thought of it.

                          :-)

                          Thank you to Fredrik for trying to teach me something, but it is 11pm on
                          the night before a public holiday (Australia Day), my house feels like an
                          oven, and in the last three hours I've suddenly started coming down with a
                          cold -- in the middle of our summer. So this is not the time for me to try
                          to learn anything new.


                          --
                          Steven.

                          Comment

                          Working...