1
\$\begingroup\$

I have a large number of images that were named in a odd way and because of that, when they're displayed in a file browser, they're completely out of order. However, since they weren't named in a completely random manner, I can use regex to properly rename them, once I understand all the subpatterns that went into it. So far I only understood two.

So I'm going to create a program to verify the pattern of each filename, make a set out of it with a sample of each name, and then try to understand the patterns and subpatterns.

def get_pattern(name):
    pattern = []
    for letter in name:
        if letter.isalpha():
            pattern.append('a')
        elif letter.isdigit():
            pattern.append('0')
        else:
            pattern.append(letter)
    return ''.join(pattern)

It's pretty straightforward to loop through the images and then check the pattern for each image.

My questions:

  1. Is there a way to make the code more concise? Maybe using a dictionary?
  2. Is there something in re or other easily available library that does this? Is using isalpha() and isdigit() the way to go here?
\$\endgroup\$
5
  • 1
    \$\begingroup\$ This code is simple, explicit and clear. You can rewrite this to be shorter with a dictionary or use map or a comprehension on name with a function that handles with a single letter but this seems fairly ok to me. \$\endgroup\$ Oct 12, 2013 at 21:33
  • 1
    \$\begingroup\$ You could do ''.join(['a' if l.isalpha() else '0' if l.isdigit() else l for l in name]), but your code is fairly clear as it is now. You could do away with constructing a list and just append characters to a string. \$\endgroup\$
    – Blender
    Oct 12, 2013 at 21:35
  • \$\begingroup\$ You may do something like >>> print map(lambda x: 'A' if x.isalpha() else x, name) \$\endgroup\$ Oct 12, 2013 at 21:36
  • \$\begingroup\$ There could be a more elegant way of renaming the images. Can you post the format? \$\endgroup\$
    – Blender
    Oct 12, 2013 at 21:42
  • \$\begingroup\$ Example of one image's name: 10400aeh09_200_eh09_b2.jpg There are many variations and more than 7k images, hence why I need to get all of them and figure out how to correctly reorder. It seemed a lot easier when I looked at it first :@ Think I'll just settle for Bender's method, unless something more elegant shows up. \$\endgroup\$
    – user975982
    Oct 12, 2013 at 22:01

3 Answers 3

1
\$\begingroup\$

This will make your example work in the same way you intended to.

patterns = []
patterns.append(lambda x: 'A' if x.isalpha() else x)
patterns.append(lambda x: '0' if x.isdigit() else x)

def get_pattern(name):
    for pattern in patterns:
        name = map(pattern, name)
    return ''.join(name)

Additionally you can register new patterns. Here is an example:

>>> get_pattern('Mario Cesar 2013')
'AAAAA AAAAA 0000'

About your objective, if you want just to sanitize the file names, will be the best to use a different approach, look at https://github.com/ksze/sanitize

\$\endgroup\$
3
  • \$\begingroup\$ Can you explain how that library helps me? I don't understand from looking at the documentation. Maybe I didn't explain my problem well. I reread it and it seems to be aimed at fixing file names that would work on linux and wouldn't on windows, for example. My problem is that they were order in an unusual, cryptic way which makes the images look completely out of order using standard alphanumberic sorting, so I need to figure out how they were sorted and rename them. However, since there are too many images, I'm using this get_pattern to make it a manageable problem. \$\endgroup\$
    – user975982
    Oct 12, 2013 at 22:09
  • \$\begingroup\$ sanitize basically just clean the filenames from special characters \$\endgroup\$ Oct 12, 2013 at 23:34
  • \$\begingroup\$ You have a special problem, right now I have no clue how to improve the process for you \$\endgroup\$ Oct 12, 2013 at 23:35
1
\$\begingroup\$

This is more compact, but not necessarily better:

def get_pattern(name):
    return ''.join([(c.isalpha() and 'a') or (c.isdigit() and '0') or c for c in name])

The parentheses are optional.

\$\endgroup\$
2
  • \$\begingroup\$ This definitively have less loops, my answer walk all the list for every pattern, the 'or' operator is a neat trick \$\endgroup\$ Oct 12, 2013 at 23:36
  • \$\begingroup\$ @MarioCésar The loops are still there, they are just implied in the list comprehensions. \$\endgroup\$ Nov 20, 2013 at 22:13
1
\$\begingroup\$

You could use map:

def get_pattern(name):
    def simplify(character):
        if character.isalpha():
            return 'a'
        elif character.isdigit():
            return '0'
        return character
    return ''.join(map(simplify, name))

... or translate:

import string
translation = string.maketrans(string.ascii_letters + string.digits,
                               'a' * len(string.ascii_letters) +
                               '0' * len(string.digits))
def get_pattern(name):
    return name.translate(translation)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.