Pau*_*ter 51 python string case-insensitive
在Python中比较字符串的最简单方法是什么,忽略大小写?
当然可以做(str1.lower()<= str2.lower())等,但是这创建了两个额外的临时字符串(具有明显的alloc/gc开销).
我想我正在寻找相当于C的stricmp().
[请求更多上下文,所以我将用一个简单的例子来证明:]
假设您要对looong字符串列表进行排序.你只需要做List.sort().这是O(n*log(n))字符串比较,没有内存管理(因为所有字符串和列表元素都是某种智能指针).你很快乐.
现在,您想要做同样的事情,但忽略这种情况(让我们简化并说所有字符串都是ascii,因此可以忽略区域设置问题).您可以执行List.sort(key = lambda s:s.lower()),但是每次比较会导致两个新的分配,加上垃圾收集器与重复(降低)字符串的负担.每个这样的存储器管理噪声比简单的字符串比较慢几个数量级.
现在,使用就地stricmp()函数,你可以:theList.sort(cmp = stricmp),它与theList.sort()一样快和内存友好.你又开心了.
问题是任何基于Python的不区分大小写的比较涉及隐式字符串重复,所以我期望找到基于C的比较(可能在模块字符串中).
找不到那样的东西,因此问题就在这里.(希望这澄清了这个问题).
小智 75
这是一个基准测试,显示使用str.lower比接受的答案的建议方法(libc.strcasecmp)更快:
#!/usr/bin/env python2.7
import random
import timeit
from ctypes import *
libc = CDLL('libc.dylib') # change to 'libc.so.6' on linux
with open('/usr/share/dict/words', 'r') as wordlist:
words = wordlist.read().splitlines()
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))
Run Code Online (Sandbox Code Playgroud)
我机器上的典型时间:
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
Run Code Online (Sandbox Code Playgroud)
因此,该版本str.lower不仅是迄今为止最快的版本,而且也是所有提议的解决方案中最便携和pythonic.我没有介绍内存使用情况,但原始海报仍然没有给出令人信服的理由担心它.另外,谁说调用libc模块不会复制任何字符串?
注意:lower()字符串方法还具有依赖于语言环境的优点.在编写自己的"优化"解决方案时,您可能无法做到正确的事情.即便如此,由于Python中的错误和缺少的功能,这种比较可能会在unicode上下文中给出错误的结果.
您是否在高性能敏感应用程序的频繁执行路径中使用此比较?或者,您是在大小为兆字节的字符串上运行吗?如果没有,那么你不应该担心性能,只需使用.lower()方法.
下面的代码演示了通过在两个字符串上调用.lower()来进行不区分大小写的比较,这两个字符串的大小几乎都是几兆字节,在我的1.8GHz桌面计算机上大约需要0.009秒:
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
Run Code Online (Sandbox Code Playgroud)
如果确实这是一个非常重要的,性能关键的代码部分,那么我建议在C中编写一个函数并从Python代码中调用它,因为这样可以让您进行真正有效的不区分大小写的搜索.有关编写C扩展模块的详细信息,请访问:https://docs.python.org/extending/extending.html
您的问题意味着您不需要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']
Run Code Online (Sandbox Code Playgroud)
澄清:如果乍一看并不明显,locale.strcoll似乎是你需要的函数,避免str.lower或locale.strxfrm"重复"字符串.
我找不到任何其他内置的不区分大小写的比较方法:python cook-book食谱使用lower().
但是,由于土耳其语I问题,因此在使用lower进行比较时必须小心.不幸的是,Python对土耳其语的处理并不好.ı转换为我,但我没有转换为ı.©转换为i,但我没有转换为İ.
pat*_*ung -11
针对您的澄清...
您可以使用ctypes来执行 c 函数“strcasecmp”。Ctypes 包含在 Python 2.5 中。它提供了调用 dll 和共享库(例如 libc)的能力。下面是一个简单示例(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
Run Code Online (Sandbox Code Playgroud)
可能还想参考strcasecmp 文档
不太确定这是更快还是更慢(尚未测试),但这是使用 C 函数进行不区分大小写的字符串比较的一种方法。
~~~~~~~~~~~~~~
ActiveState 代码 - 配方 194371:不区分大小写的字符串 是创建不区分大小写的字符串类的配方。对于快速的东西来说,这可能有点过头了,但如果您打算经常使用它们,它可以为您提供处理不区分大小写的字符串的通用方法。
| 归档时间: |
|
| 查看次数: |
101501 次 |
| 最近记录: |