Recipe 1.9. Simplifying Usage of Strings' translate MethodCredit: Chris Perkins, Raymond Hettinger ProblemYou often want to use the fast code in strings' TRanslate method, but find it hard to remember in detail how that method and the function string.maketrans work, so you want a handy facade to simplify their use in typical cases. SolutionThe TRanslate method of strings is quite powerful and flexible, as detailed in Recipe 1.10. However, exactly because of that power and flexibility, it may be a nice idea to front it with a "facade" that simplifies its typical use. A little factory function, returning a closure, can do wonders for this kind of task: import string def translator(frm='', to='', delete='', keep=None): if len(to) == 1: to = to * len(frm) trans = string.maketrans(frm, to) if keep is not None: allchars = string.maketrans('', '') delete = allchars.translate(allchars, keep.translate(allchars, delete)) def translate(s): return s.translate(trans, delete) return translate DiscussionI often find myself wanting to use strings' translate method for any one of a few purposes, but each time I have to stop and think about the details (see Recipe 1.10 for more information about those details). So, I wrote myself a class (later remade into the factory closure presented in this recipe's Solution) to encapsulate various possibilities behind a simpler-to-use facade. Now, when I want a function that keeps only characters from a given set, I can easily build and use that function: >>> digits_only = translator(keep=string.digits) >>> digits_only('Chris Perkins : 224-7992') '2247992' It's similarly simple when I want to remove a set of characters: >>> no_digits = translator(delete=string.digits) >>> no_digits('Chris Perkins : 224-7992') 'Chris Perkins : -' and when I want to replace a set of characters with a single character: >>> digits_to_hash = translator(from=string.digits, to='#') >>> digits_to_hash('Chris Perkins : 224-7992') 'Chris Perkins : ###-####' While the latter may appear to be a bit of a special case, it is a task that keeps coming up for me every once in a while. I had to make one arbitrary design decision in this recipenamely, I decided that the delete parameter "trumps" the keep parameter if they overlap: >>> trans = translator(delete='abcd', keep='cdef') >>> trans('abcdefg') 'ef' For your applications it might be preferable to ignore delete if keep is specified, or, perhaps better, to raise an exception if they are both specified, since it may not make much sense to let them both be given in the same call to translator, anyway. Also: as noted in Recipe 1.8 and Recipe 1.10, the code in this recipe works only for normal strings, not for Unicode strings. See Recipe 1.10 to learn how to code this kind of functionality for Unicode strings, whose translate method is different from that of plain (i.e., byte) strings.
See AlsoRecipe 1.10 for a direct equivalent of this recipe's TRanslator(keep=...), more information on the TRanslate method, and an equivalent approach for Unicode strings; documentation for strings' translate method, and for the maketrans function in the string module, in the Library Reference and Python in a Nutshell. |