2007-06-29
Python Cookbook 1.24 让字符串大小写不敏感
需求:
要处理一个字符串,需要让它对大小写不敏感,如字符串查找和比较等.而其它的字符串依然保持原来的特性.
讨论:
最好的办法就是从str继承一个子类来处理.
class iStr(str):
"""
Case insensitive string class.
Behaves just like str, except that all comparisons and lookups
are case insensitive.
"""
def _ _init_ _(self, *args):
self._lowered = str.lower(self)
def _ _repr_ _(self):
return '%s(%s)' % (type(self)._ _name_ _, str._ _repr_ _(self))
def _ _hash_ _(self):
return hash(self._lowered)
def lower(self):
return self._lowered
def _make_case_insensitive(name):
''' wrap one method of str into an iStr one, case-insensitive '''
str_meth = getattr(str, name)
def x(self, other, *args):
''' try lowercasing 'other', which is typically a string, but
be prepared to use it as-is if lowering gives problems,
since strings CAN be correctly compared with non-strings.
'''
try: other = other.lower( )
except (TypeError, AttributeError, ValueError): pass
return str_meth(self._lowered, other, *args)
# in Python 2.4, only, add the statement: x.func_name = name
setattr(iStr, name, x)
# apply the _make_case_insensitive function to specified methods
for name in 'eq lt le gt gt ne cmp contains'.split( ):
_make_case_insensitive('_ _%s_ _' % name)
for name in 'count endswith find index rfind rindex startswith'.split( ):
_make_case_insensitive(name)
# note that we don't modify methods 'replace', 'split', 'strip', ...
# of course, you can add modifications to them, too, if you prefer that.
del _make_case_insensitive # remove helper function, not needed any more
在类iStr中有一些要点需要注意.首先,我们在初始化的时候生成了需要处理字符串的小写版本,在__init__方法中这样做,是因为iStr对象要重复使用, 这样处理可以提高效率.我们使用一个下划线来标识这个变量,而不是两个,让它对子类可见,对外部不可见.
在这里并没有提供有些方法的大小写不敏感版本,因为很难在一般情况下确定具体的需求.在具体的应用中,子类可以根据自己的需求做特定的处理.举例说明,如果子类写了一个针对iStr的replace方法,而它的返回值是str类型,如果想要让所有的返回值也是iStr类型,需要写一个助手函数来处理:
def _make_return_iStr(name):
str_meth = getattr(str, name)
def x(*args):
return iStr(str_meth(*args))
setattr(iStr, name, x)
然后你需要针对特定的字符串方法调用这个函数:
for name in 'center ljust rjust strip lstrip rstrip'.split( ):
_make_return_iStr(name)
String大约有20个相关方法(包括__add__和__mul__),有些是需要你封装的.如果你想封装更多的方法,要进行更多的处理,比如split和join,或者encode和decode,你需要从unicode继承子类,而不是str.
在上例中,我们尽量避免使用模板代码.只需要在特定应用的时候重写iStr的方法就可以了.自己重写一个类,也不会带来更多的好处.
在Python2.4以及以后的版本,你可以将一个方法赋值给一个函数对象.这样,就可以获得更好的可读性较高的代码,尤其是在函数叠加使用的时候.在Python2.3中,函数对象是只读的,在这里我们避免改变函数对象的值,已防止兼容性的问题.
大小写无关(并不改变大小写)有很多用处,比如在检查用户输入,或者有些文件系统上(windows和Macintosh), 文件名都是不区分大小写的.你可以很容易的为自己创建大小写无关的列表,字典,集合等.
举例说明,一个列表里面保存了一些字符串,而需要用一些大小写无关的方法来处理他们,如排序,索引等.可以构造iStr来处理它们:
class iList(list):
def _ _init_ _(self, *args):
list._ _init_ _(self, *args)
# rely on _ _setitem_ _ to wrap each item into iStr...
self[:] = self
wrap_each_item = iStr
def _ _setitem_ _(self, i, v):
if isinstance(i, slice): v = map( self.wrap_each_item, v)
else: v = self.wrap_each_item(v)
list._ _setitem_ _(self, i, v)
def append(self, item):
list.append(self, self.wrap_each_item(item))
def extend(self, seq):
list.extend(self, map(self.wrap_each_item, seq))
基本上,我们确保了iList中的每一个对象都被iStr封装了.
要处理一个字符串,需要让它对大小写不敏感,如字符串查找和比较等.而其它的字符串依然保持原来的特性.
讨论:
最好的办法就是从str继承一个子类来处理.
class iStr(str):
"""
Case insensitive string class.
Behaves just like str, except that all comparisons and lookups
are case insensitive.
"""
def _ _init_ _(self, *args):
self._lowered = str.lower(self)
def _ _repr_ _(self):
return '%s(%s)' % (type(self)._ _name_ _, str._ _repr_ _(self))
def _ _hash_ _(self):
return hash(self._lowered)
def lower(self):
return self._lowered
def _make_case_insensitive(name):
''' wrap one method of str into an iStr one, case-insensitive '''
str_meth = getattr(str, name)
def x(self, other, *args):
''' try lowercasing 'other', which is typically a string, but
be prepared to use it as-is if lowering gives problems,
since strings CAN be correctly compared with non-strings.
'''
try: other = other.lower( )
except (TypeError, AttributeError, ValueError): pass
return str_meth(self._lowered, other, *args)
# in Python 2.4, only, add the statement: x.func_name = name
setattr(iStr, name, x)
# apply the _make_case_insensitive function to specified methods
for name in 'eq lt le gt gt ne cmp contains'.split( ):
_make_case_insensitive('_ _%s_ _' % name)
for name in 'count endswith find index rfind rindex startswith'.split( ):
_make_case_insensitive(name)
# note that we don't modify methods 'replace', 'split', 'strip', ...
# of course, you can add modifications to them, too, if you prefer that.
del _make_case_insensitive # remove helper function, not needed any more
在类iStr中有一些要点需要注意.首先,我们在初始化的时候生成了需要处理字符串的小写版本,在__init__方法中这样做,是因为iStr对象要重复使用, 这样处理可以提高效率.我们使用一个下划线来标识这个变量,而不是两个,让它对子类可见,对外部不可见.
在这里并没有提供有些方法的大小写不敏感版本,因为很难在一般情况下确定具体的需求.在具体的应用中,子类可以根据自己的需求做特定的处理.举例说明,如果子类写了一个针对iStr的replace方法,而它的返回值是str类型,如果想要让所有的返回值也是iStr类型,需要写一个助手函数来处理:
def _make_return_iStr(name):
str_meth = getattr(str, name)
def x(*args):
return iStr(str_meth(*args))
setattr(iStr, name, x)
然后你需要针对特定的字符串方法调用这个函数:
for name in 'center ljust rjust strip lstrip rstrip'.split( ):
_make_return_iStr(name)
String大约有20个相关方法(包括__add__和__mul__),有些是需要你封装的.如果你想封装更多的方法,要进行更多的处理,比如split和join,或者encode和decode,你需要从unicode继承子类,而不是str.
在上例中,我们尽量避免使用模板代码.只需要在特定应用的时候重写iStr的方法就可以了.自己重写一个类,也不会带来更多的好处.
在Python2.4以及以后的版本,你可以将一个方法赋值给一个函数对象.这样,就可以获得更好的可读性较高的代码,尤其是在函数叠加使用的时候.在Python2.3中,函数对象是只读的,在这里我们避免改变函数对象的值,已防止兼容性的问题.
大小写无关(并不改变大小写)有很多用处,比如在检查用户输入,或者有些文件系统上(windows和Macintosh), 文件名都是不区分大小写的.你可以很容易的为自己创建大小写无关的列表,字典,集合等.
举例说明,一个列表里面保存了一些字符串,而需要用一些大小写无关的方法来处理他们,如排序,索引等.可以构造iStr来处理它们:
class iList(list):
def _ _init_ _(self, *args):
list._ _init_ _(self, *args)
# rely on _ _setitem_ _ to wrap each item into iStr...
self[:] = self
wrap_each_item = iStr
def _ _setitem_ _(self, i, v):
if isinstance(i, slice): v = map( self.wrap_each_item, v)
else: v = self.wrap_each_item(v)
list._ _setitem_ _(self, i, v)
def append(self, item):
list.append(self, self.wrap_each_item(item))
def extend(self, seq):
list.extend(self, map(self.wrap_each_item, seq))
基本上,我们确保了iList中的每一个对象都被iStr封装了.
标签: Python