忽略Pythonstring中的大小写

什么是比较Python中的string最简单的方法,忽略大小写?

当然可以做(str1.lower()<= str2.lower())等等,但是这创build了两个额外的临时string(具有明显的alloc / gc开销)。

我想我正在寻找一个相当于C的stricmp()。

[请求更多的上下文,所以我将用一个简单的例子来演示:]

假设你想对一个串列表进行sorting。 你只需要做List.sort()。 这是O(n * log(n))string比较,没有内存pipe理(因为所有的string和列表元素都是某种智能指针)。 你很快乐。

现在,你想要做同样的事情,但忽略这种情况(让我们简化并说所有的string都是ascii,所以locale问题可以忽略)。 您可以执行List.sort(key = lambda s:s.lower()),但是这会导致每个比较有两个新的分配,加上垃圾收集器和重复(降低)的string。 每个这样的内存pipe理噪声比简单的string比较要慢几个数量级。

现在,使用就地stricmp()函数,您可以:theList.sort(cmp = stricmp),它和列表.sort()一样快速且友好。 你又开心了

问题是任何基于Python的不区分大小写的比较涉及隐式string重复,所以我期待find一个基于C的比较(可能在模块string中)。

找不到像这样的东西,因此这里的问题。 (希望澄清这个问题)。

为了回应你的澄清…

你可以使用ctypes来执行c函数“strcasecmp”。 Ctypes包含在Python 2.5中。 它提供了调用dll和共享库(如libc)的function。 下面是一个简单的例子(Linux上的Python;请参阅Win32帮助的链接):

 from ctypes import * libc = CDLL("libc.so.6") // see link above for Win32 help libc.strcasecmp("THIS", "this") // returns 0 libc.strcasecmp("THIS", "THAT") // returns 8 

也可能要引用strcasecmp文档

不确定这是更快还是更慢(还没有testing过),但是这是一种使用C函数执行不区分大小写的string比较的方法。

~~~~~~~~~~~~~~

ActiveState代码 – 配方194371:不区分大小写string是创build一个不区分大小写的string类的配方。 如果你打算经常使用这些string,可能会有点过分,但是可以为你提供处理大小写不敏感的string的常用方法。

这是一个基准,显示使用str.lower比接受的答案build议的方法( libc.strcasecmp )更快:

 #/usr/bin/env python2.5 import random import timeit from ctypes import * libc = CDLL("libc.dylib") # change to "libc.so.6" on linux words = [word.rstrip() for word in open('/usr/share/dict/words', 'r').readlines()] random.shuffle(words) print '%i words in list' % len(words) setup = 'from __main__ import words, libc; gc.enable()' stmts = [ ("simple sort", "sorted(words)"), ("sort with key=str.lower", "sorted(words, key=str.lower)"), ("sort with cmp=libc.strcasecmp", "sorted(words, cmp=libc.strcasecmp)"), ] for (comment, stmt) in stmts: t = timeit.Timer(stmt=stmt, setup=setup) print "%s: %.2f msec/pass" % (comment, (1000*t.timeit(10)/10)) 

我机器上的典型时间:

 235886 words in list simple sort: 483.59 msec/pass sort with key=str.lower: 1064.70 msec/pass sort with cmp=libc.strcasecmp: 5487.86 msec/pass 

所以, str.lower的版本不仅是迄今为止最快的版本,而且也是所有提出的解决scheme中最具可移植性和pythonic的。 我还没有分析内存使用情况,但原来的海报仍然没有给出令人信服的理由担心。 另外,谁说,调用libc模块不会重复任何string?

注意: lower()string方法也具有依赖语言环境的优点。 在编写自己的“优化”解决scheme时,你可能不会得到正确的结果。 即使如此,由于Python中的错误和缺less的function,这种比较可能会在unicode上下文中给出错误的结果。

你的问题意味着你不需要Unicode。 尝试下面的代码片段; 如果它适合你,你就完成了:

 Python 2.5.2 (r252:60911, Aug 22 2008, 02:34:17) [GCC 4.3.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import locale >>> locale.setlocale(locale.LC_COLLATE, "en_US") 'en_US' >>> sorted("ABCabc", key=locale.strxfrm) ['a', 'A', 'b', 'B', 'c', 'C'] >>> sorted("ABCabc", cmp=locale.strcoll) ['a', 'A', 'b', 'B', 'c', 'C'] 

澄清:如果一见钟情不明显,locale.strcoll似乎是您需要的函数,避免了str.lower或locale.strxfrm“重复”string。

您是否在一个高性能敏感应用程序的经常执行的path中使用这个比较? 或者,你是在字节上运行这是兆字节的大小? 如果没有,那么你不应该担心性能,只使用.lower()方法。

下面的代码演示了通过调用每个几乎是兆字节大小的两个string上的.lower(),在我的1.8GHz桌面计算机上执行大小写不敏感的比较:

 from timeit import Timer s1 = "1234567890" * 100000 + "a" s2 = "1234567890" * 100000 + "B" code = "s1.lower() < s2.lower()" time = Timer(code, "from __main__ import s1, s2").timeit(1000) print time / 1000 # 0.00920499992371 on my machine 

如果确实这是一个非常重要的,性能至关重要的代码部分,那么我build议在C中编写一个函数,并从Python代码中调用它,因为这样可以让您进行真正高效的不区分大小写的search。 编写C扩展模块的细节可以在这里find: https : //docs.python.org/extending/extending.html

我找不到任何其他内置的方式来区分大小写比较: python cook-book recipe使用lower()。

但是,由于土耳其语问题,在使用较低值进行比较时,您必须小心。 不幸的是,Python对于土耳其语的处理并不好。 我转换为我,但我不转换为我。 我转换为我,但我没有转换为©。

没有内置的相当于你想要的function。

您可以编写自己的函数,每次转换为.lower(),避免重复这两个string,但是我相信它会非常耗费CPU资源,效率极低。

除非你正在使用非常长的string(如果重复的话可能会导致内存问题),那么我会保持简单和使用

 str1.lower() == str2.lower() 

你会没事的

这个问题提出了两个完全不同的东西:

  1. 在Python中比较string的最简单方法是忽略大小写?
  2. 我想我正在寻找一个相当于C的stricmp()。

因为#1已经被很好地回答了(即:str1.lower()<str2.lower()),我会回答#2。

 def strincmp(str1, str2, numchars=None): result = 0 len1 = len(str1) len2 = len(str2) if numchars is not None: minlen = min(len1,len2,numchars) else: minlen = min(len1,len2) #end if orda = ord('a') ordz = ord('z') i = 0 while i < minlen and 0 == result: ord1 = ord(str1[i]) ord2 = ord(str2[i]) if ord1 >= orda and ord1 <= ordz: ord1 = ord1-32 #end if if ord2 >= orda and ord2 <= ordz: ord2 = ord2-32 #end if result = cmp(ord1, ord2) i += 1 #end while if 0 == result and minlen != numchars: if len1 < len2: result = -1 elif len2 < len1: result = 1 #end if #end if return result #end def 

只有在有意义的情况下才使用这个函数,因为在许多情况下,小写字母技术会更好。

我只使用asciistring,我不知道这将如何与unicode行为。

当标准库中的某些东西不被很好的支持时,我总是寻找一个PyPI包。 随着虚拟化和现代Linux发行版的普及,我不再避免Python扩展。 PyICU似乎符合这个法案: https ://stackoverflow.com/a/1098160/3461

现在还有一个选项是纯Python。 它被很好地testing: https : //github.com/jtauber/pyuca


老答案:

我喜欢正则expression式的解决scheme。 这里有一个函数可以复制并粘贴到任何函数中,这要感谢python的块结构支持。

 def equals_ignore_case(str1, str2): import re return re.match(re.escape(str1) + r'\Z', str2, re.I) is not None 

由于我使用了匹配而不是search,因此我不需要在正则expression式中添加脱字号(^)。

注意:这只会检查平等,有时候这是需要的。 我也不会说我喜欢它。

这是你怎么做的重新:

 import re p = re.compile('^hello$', re.I) p.match('Hello') p.match('hello') p.match('HELLO') 

使用昂贵的计算键来对值列表进行sorting的推荐方式是所谓的“装饰模式”。 它只是简单地从原始列表中构build(键,值)元组的列表,并对该列表进行sorting。 然后消除键和获得sorting值列表是微不足道的:

 >>> original_list = ['a', 'b', 'A', 'B'] >>> decorated = [(s.lower(), s) for s in original_list] >>> decorated.sort() >>> sorted_list = [s[1] for s in decorated] >>> sorted_list ['A', 'a', 'B', 'b'] 

或者如果你喜欢单线游戏:

 >>> sorted_list = [s[1] for s in sorted((s.lower(), s) for s in original_list)] >>> sorted_list ['A', 'a', 'B', 'b'] 

如果你真的担心调用lower()的代价,你可以在任何地方存储(降低string,原始string)的元组。 元组是Python中最便宜的一种容器,它们也是可散列的,所以它们可以用作字典键,集合成员等等。

我很确定你要么使用.lower(),要么使用正则expression式。 我不知道内置的不区分大小写的string比较函数。

对于偶尔的甚至是重复的比较,只要核心代码最内层的循环不会发生一些额外的string对象,或者没有足够的数据来实际地注意到性能的影响。 看看你是否这样做:以“愚蠢”的方式做事情,如果你也做得less,就不那么愚蠢了。

如果你真的想要不断地比较大量和大量的文本,你可以以某种方式保持string的小写版本,以避免最终化和重新创build,或将整个数据集规范化为小写。 这当然取决于数据集的大小。 如果有相对较less的针和大草垛,用编译的正则expression式对象replace针是一种解决scheme。 如果没有看到一个具体的例子很难说。

你可以将每个string翻译成小写,只有在你需要的时候,才会懒散地翻译,或者如果你知道你将要sorting整个string的集合的话,就可以把它们翻译成这种types。 有几种方法可以将这个比较键附加到正在sorting的实际数据上,但这些技术应该在单独的问题中解决。

请注意,这种技术不仅可以用来处理大小写问题,而且可以用于其他types的sorting,比如区域特定的sorting,或者“Library-style”标题sorting,这些sorting忽略了领先的文章,或者在sorting之前对数据进行规范化。

只要使用str().lower()方法,除非高性能很重要 – 在这种情况下,将该sorting方法写为C扩展。

“如何编写Python扩展”看起来像一个体面的介绍..

更有趣的是, 本指南比较了使用ctypes库vs写入外部C模块(ctype比C扩展相当慢)。

 import re if re.match('tEXT', 'text', re.IGNORECASE): # is True 

你可以子类str和创build自己的不区分大小写的string类,但恕我直言,这将是非常不明智的,创造更多的麻烦比它的价值。