Recipe1.9.Simplifying Usage of Strings translate Method


Recipe 1.9. Simplifying Usage of Strings' translate Method

Credit: Chris Perkins, Raymond Hettinger

Problem

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

Solution

The 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

Discussion

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

Closures

A closure is nothing terribly complicated: just an "inner" function that refers to names (variables) that are local to an "outer" function containing it. Canonical toy-level example:

def make_adder(addend):     def adder(augend): return augend+addend     return adder

Executing p = make_adder(23) makes a closure of inner function adder internally referring to a name addend that is bound to the value 23. Then, q = make_adder(42) makes another closure, for which, internally, name addend is instead bound to the value 42. Making q in no way interferes with p, they can happily and independently coexist. So we can now execute, say, print p(100), q(100) and enjoy the output 123 142.

In practice, you may often see make_adder referred to as a closure rather than by the pedantic, ponderous periphrasis "a function that returns a closure"fortunately, context often clarifies the situation. Calling make_adder a factory (or factory function) is both accurate and concise; you may also say it's a closure factory to specify it builds and returns closures, rather than, say, classes or class instances.


See Also

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



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net