<p>What is the easiest way to compare strings in Python, ignoring case?</p>

<p>Of course one can do (str1.lower() &lt;= str2.lower()), etc., but this created two additional temporary strings (with the obvious alloc/g-c overheads).</p>

<p>I guess I'm looking for an equivalent to C's stricmp().</p>

<p>[Some more context requested, so I'll demonstrate with a trivial example:]</p>

<p>Suppose you want to sort a looong list of strings. You simply do theList.sort().
This is O(n * log(n)) string comparisons and no memory management (since all
strings and list elements are some sort of smart pointers). You are happy.</p>

<p>Now, you want to do the same, but ignore the case (let's simplify and say
all strings are ascii, so locale issues can be ignored).
You can do theList.sort(key=lambda s: s.lower()), but then you cause two new 
allocations per comparison, plus burden the garbage-collector with the duplicated
(lowered) strings. 
Each such memory-management noise is orders-of-magnitude slower than simple string comparison.</p>

<p>Now, with an in-place stricmp()-like function, you do: theList.sort(cmp=stricmp)
and it is as fast and as memory-friendly as theList.sort(). You are happy again.</p>

<p>The problem is any Python-based case-insensitive comparison involves implicit string 
duplications, so I was expecting to find a C-based comparisons (maybe in module string).</p>

<p>Could not find anything like that, hence the question here.
(Hope this clarifies the question).</p>

[{'answer_id': 62592, 'author': 'Mark Biek', 'author_id': 305, 'author_profile': 'https://Stackoverflow.com/users/305', 'pm_score': 0, 'selected': False, 'text': "<p>I'm pretty sure you either have to use .lower() or use a regular expression.  I'm not aware of a built-in case-insensitive string comparison function.</p>\n"}, {'answer_id': 62647, 'author': 'Moses Ting', 'author_id': 7056, 'author_profile': 'https://Stackoverflow.com/users/7056', 'pm_score': 1, 'selected': False, 'text': "<p>This is how you'd do it with re:</p>\n\n<pre><code>import re\np = re.compile('^hello$', re.I)\np.match('Hello')\np.match('hello')\np.match('HELLO')\n</code></pre>\n"}, {'answer_id': 62652, 'author': 'David Webb', 'author_id': 3171, 'author_profile': 'https://Stackoverflow.com/users/3171', 'pm_score': -1, 'selected': False, 'text': "<p>You could subclass <code>str</code> and create your own case-insenstive string class but IMHO that would be extremely unwise and create far more trouble than it's worth.</p>\n"}, {'answer_id': 62983, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 0, 'selected': False, 'text': '<p>For occasional or even repeated comparisons, a few extra string objects shouldn\'t matter as long as this won\'t happen in the innermost loop of your core code or you don\'t have enough data to actually notice the performance impact. See if you do: doing things in a "stupid" way is much less stupid if you also do it less.</p>\n\n<p>If you seriously want to keep comparing lots and lots of text case-insensitively you could somehow keep the lowercase versions of the strings at hand to avoid finalization and re-creation, or normalize the whole data set into lowercase. This of course depends on the size of the data set. If there are a relatively few needles and a large haystack, replacing the needles with compiled regexp objects is one solution. If It\'s hard to say without seeing a concrete example.</p>\n'}, {'answer_id': 63007, 'author': 'Ricardo Reyes', 'author_id': 3399, 'author_profile': 'https://Stackoverflow.com/users/3399', 'pm_score': 2, 'selected': False, 'text': "<p>There's no built in equivalent to that function you want.</p>\n\n<p>You can write your own function that converts to .lower() each character at a time to avoid  duplicating both strings, but I'm sure it will very cpu-intensive and extremely inefficient. </p>\n\n<p>Unless you are working with extremely long strings (so long that can cause a memory problem if duplicated) then I would keep it simple and use </p>\n\n<pre><code>str1.lower() == str2.lower()\n</code></pre>\n\n<p>You'll be ok</p>\n"}, {'answer_id': 63071, 'author': 'Eli Courtwright', 'author_id': 1694, 'author_profile': 'https://Stackoverflow.com/users/1694', 'pm_score': 3, 'selected': False, 'text': '<p>Are you using this compare in a very-frequently-executed path of a highly-performance-sensitive application?  Alternatively, are you running this on strings which are megabytes in size?  If not, then you shouldn\'t worry about the performance and just use the .lower() method.</p>\n\n<p>The following code demonstrates that doing a case-insensitive compare by calling .lower() on two strings which are each almost a megabyte in size takes about 0.009 seconds on my 1.8GHz desktop computer:</p>\n\n<pre><code>from timeit import Timer\n\ns1 = "1234567890" * 100000 + "a"\ns2 = "1234567890" * 100000 + "B"\n\ncode = "s1.lower() &lt; s2.lower()"\ntime = Timer(code, "from __main__ import s1, s2").timeit(1000)\nprint time / 1000   # 0.00920499992371 on my machine\n</code></pre>\n\n<p>If indeed this is an extremely significant, performance-critical section of code, then I recommend writing a function in C and calling it from your Python code, since that will allow you to do a truly efficient case-insensitive search.  Details on writing C extension modules can be found here: <a href="https://docs.python.org/extending/extending.html" rel="nofollow noreferrer">https://docs.python.org/extending/extending.html</a></p>\n'}, {'answer_id': 63820, 'author': 'Douglas Leeder', 'author_id': 3978, 'author_profile': 'https://Stackoverflow.com/users/3978', 'pm_score': 3, 'selected': False, 'text': '<p>I can\'t find any other built-in way of doing case-insensitive comparison: The <a href="http://code.activestate.com/recipes/170242/" rel="noreferrer">python cook-book recipe</a> uses lower().</p>\n\n<p>However you have to be careful when using lower for comparisons because of the <a href="http://en.wikipedia.org/wiki/Turkish_dotted_and_dotless_I" rel="noreferrer">Turkish I problem</a>. Unfortunately Python\'s handling for Turkish Is is not good. ı is converted to I, but I is not converted to ı. İ is converted to i, but i is not converted to İ. </p>\n'}, {'answer_id': 65834, 'author': 'Dale Wilson', 'author_id': 391806, 'author_profile': 'https://Stackoverflow.com/users/391806', 'pm_score': 0, 'selected': False, 'text': '<p>You could translate each string to lowercase once --- lazily only when you need it, or as a prepass to the sort if you know you\'ll be sorting the entire collection of strings.  There are several ways to attach this comparison key to the actual data being sorted, but these techniques should be addressed in a separate issue.</p>\n\n<p>Note that this technique can be used not only to handle upper/lower case issues, but for other types of sorting such as locale specific sorting, or "Library-style" title sorting that ignores leading articles and otherwise normalizes the data before sorting it.</p>\n'}, {'answer_id': 66547, 'author': 'patrickyoung', 'author_id': 3701, 'author_profile': 'https://Stackoverflow.com/users/3701', 'pm_score': -1, 'selected': True, 'text': '<p>In response to your clarification...</p>\n\n<p>You could use <a href="http://docs.python.org/lib/ctypes-ctypes-tutorial.html" rel="nofollow noreferrer">ctypes</a> to execute the c function "strcasecmp".  Ctypes is included in Python 2.5.  It provides the ability to call out to dll and shared libraries such as libc. Here is a quick example (Python on Linux; see link for Win32 help):</p>\n\n<pre><code>from ctypes import *\nlibc = CDLL("libc.so.6")  // see link above for Win32 help\nlibc.strcasecmp("THIS", "this") // returns 0\nlibc.strcasecmp("THIS", "THAT") // returns 8\n</code></pre>\n\n<p>may also want to reference <a href="http://linux.die.net/man/3/strcasecmp" rel="nofollow noreferrer">strcasecmp documentation</a></p>\n\n<p>Not really sure this is any faster or slower (have not tested), but it\'s a way to use a C function to do case insensitive string comparisons. </p>\n\n<p>~~~~~~~~~~~~~~</p>\n\n<p><a href="http://code.activestate.com/recipes/194371/" rel="nofollow noreferrer" title="ActiveState Code">ActiveState Code - Recipe 194371: Case Insensitive Strings</a>\nis a recipe for creating a case insensitive string class.  It might be a bit over kill for something quick, but could provide you with a common way of handling case insensitive strings if you plan on using them often.</p>\n'}, {'answer_id': 67388, 'author': 'Antoine P.', 'author_id': 10194, 'author_profile': 'https://Stackoverflow.com/users/10194', 'pm_score': 1, 'selected': False, 'text': '<p>The recommended idiom to sort lists of values using expensive-to-compute keys is to the so-called "decorated pattern". It consists simply in building a list of (key, value) tuples from the original list, and sort that list. Then it is trivial to eliminate the keys and get the list of sorted values:</p>\n\n<pre><code>&gt;&gt;&gt; original_list = [\'a\', \'b\', \'A\', \'B\']\n&gt;&gt;&gt; decorated = [(s.lower(), s) for s in original_list]\n&gt;&gt;&gt; decorated.sort()\n&gt;&gt;&gt; sorted_list = [s[1] for s in decorated]\n&gt;&gt;&gt; sorted_list\n[\'A\', \'a\', \'B\', \'b\']\n</code></pre>\n\n<p>Or if you like one-liners:</p>\n\n<pre><code>&gt;&gt;&gt; sorted_list = [s[1] for s in sorted((s.lower(), s) for s in original_list)]\n&gt;&gt;&gt; sorted_list\n[\'A\', \'a\', \'B\', \'b\']\n</code></pre>\n\n<p>If you really worry about the cost of calling lower(), you can just store tuples of (lowered string, original string) everywhere. Tuples are the cheapest kind of containers in Python, they are also hashable so they can be used as dictionary keys, set members, etc.</p>\n'}, {'answer_id': 67583, 'author': 'tzot', 'author_id': 6899, 'author_profile': 'https://Stackoverflow.com/users/6899', 'pm_score': 3, 'selected': False, 'text': '<p>Your question implies that you don\'t need Unicode. Try the following code snippet; if it works for you, you\'re done:</p>\n\n<pre><code>Python 2.5.2 (r252:60911, Aug 22 2008, 02:34:17)\n[GCC 4.3.1] on linux2\nType "help", "copyright", "credits" or "license" for more information.\n&gt;&gt;&gt; import locale\n&gt;&gt;&gt; locale.setlocale(locale.LC_COLLATE, "en_US")\n\'en_US\'\n&gt;&gt;&gt; sorted("ABCabc", key=locale.strxfrm)\n[\'a\', \'A\', \'b\', \'B\', \'c\', \'C\']\n&gt;&gt;&gt; sorted("ABCabc", cmp=locale.strcoll)\n[\'a\', \'A\', \'b\', \'B\', \'c\', \'C\']\n</code></pre>\n\n<p>Clarification: in case it is not obvious at first sight, locale.strcoll seems to be the function you need, avoiding the str.lower or locale.strxfrm "duplicate" strings.</p>\n'}, {'answer_id': 121364, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 6, 'selected': False, 'text': '<p>Here is a benchmark showing that using <a href="http://docs.python.org/2/library/string.html?highlight=lower#string.lower" rel="nofollow noreferrer"><code>str.lower</code></a> is faster than the accepted answer\'s proposed method (<code>libc.strcasecmp</code>):</p>\n\n<pre><code>#!/usr/bin/env python2.7\nimport random\nimport timeit\n\nfrom ctypes import *\nlibc = CDLL(\'libc.dylib\') # change to \'libc.so.6\' on linux\n\nwith open(\'/usr/share/dict/words\', \'r\') as wordlist:\n    words = wordlist.read().splitlines()\nrandom.shuffle(words)\nprint \'%i words in list\' % len(words)\n\nsetup = \'from __main__ import words, libc; gc.enable()\'\nstmts = [\n    (\'simple sort\', \'sorted(words)\'),\n    (\'sort with key=str.lower\', \'sorted(words, key=str.lower)\'),\n    (\'sort with cmp=libc.strcasecmp\', \'sorted(words, cmp=libc.strcasecmp)\'),\n]\n\nfor (comment, stmt) in stmts:\n    t = timeit.Timer(stmt=stmt, setup=setup)\n    print \'%s: %.2f msec/pass\' % (comment, (1000*t.timeit(10)/10))\n</code></pre>\n\n<p>typical times on my machine:</p>\n\n<pre><code>235886 words in list\nsimple sort: 483.59 msec/pass\nsort with key=str.lower: 1064.70 msec/pass\nsort with cmp=libc.strcasecmp: 5487.86 msec/pass\n</code></pre>\n\n<p>So, the version with <code>str.lower</code> is not only the fastest by far, but also the most portable and pythonic of all the proposed solutions here.\nI have not profiled memory usage, but the original poster has still not given a compelling reason to worry about it. Also, who says that a call into the libc module doesn\'t duplicate any strings?</p>\n\n<p>NB: The <code>lower()</code> string method also has the advantage of being locale-dependent. Something you will probably not be getting right when writing your own "optimised" solution. Even so, due to bugs and missing features in Python, this kind of comparison may give you wrong results in a unicode context.</p>\n'}, {'answer_id': 193863, 'author': 'dbr', 'author_id': 745, 'author_profile': 'https://Stackoverflow.com/users/745', 'pm_score': 0, 'selected': False, 'text': '<p>Just use the <code>str().lower()</code> method, unless high-performance is important - in which case write that sorting method as a C extension.</p>\n\n<p><a href="http://starship.python.net/crew/arcege/extwriting/pyext.html" rel="nofollow noreferrer">"How to write a Python Extension"</a> seems like a decent intro..</p>\n\n<p>More interestingly, <a href="http://www.dalkescientific.com/writings/NBN/c_extensions.html" rel="nofollow noreferrer">This guide</a> compares using the ctypes library vs writing an external C module (the ctype is quite-substantially slower than the C extension).</p>\n'}, {'answer_id': 2711031, 'author': 'Benjamin Atkin', 'author_id': 3461, 'author_profile': 'https://Stackoverflow.com/users/3461', 'pm_score': 2, 'selected': False, 'text': '<p>When something isn\'t supported well in the standard library, I always look for a PyPI package. With virtualization and the ubiquity of modern Linux distributions, I no longer avoid Python extensions. PyICU seems to fit the bill: <a href="https://stackoverflow.com/a/1098160/3461">https://stackoverflow.com/a/1098160/3461</a></p>\n\n<p>There now is also an option that is pure python. It\'s well tested: <a href="https://github.com/jtauber/pyuca" rel="nofollow noreferrer">https://github.com/jtauber/pyuca</a></p>\n\n<hr>\n\n<p><strong>Old answer:</strong></p>\n\n<p>I like the regular expression solution. Here\'s a function you can copy and paste into any function, thanks to python\'s block structure support.</p>\n\n<pre><code>def equals_ignore_case(str1, str2):\n    import re\n    return re.match(re.escape(str1) + r\'\\Z\', str2, re.I) is not None\n</code></pre>\n\n<p>Since I used match instead of search, I didn\'t need to add a caret (^) to the regular expression.</p>\n\n<p><strong>Note:</strong> This only checks equality, which is sometimes what is needed. I also wouldn\'t go so far as to say that I like it.</p>\n'}, {'answer_id': 7239139, 'author': 'trevorcroft', 'author_id': 919044, 'author_profile': 'https://Stackoverflow.com/users/919044', 'pm_score': 2, 'selected': False, 'text': "<p>This question is asking 2 very different things:</p>\n\n<ol>\n<li>What is the easiest way to compare strings in Python, ignoring case?</li>\n<li>I guess I'm looking for an equivalent to C's stricmp().</li>\n</ol>\n\n<p>Since #1 has been answered very well already (ie: str1.lower() &lt; str2.lower())  I will answer #2.</p>\n\n<pre><code>def strincmp(str1, str2, numchars=None):\n    result = 0\n    len1 = len(str1)\n    len2 = len(str2)\n    if numchars is not None:\n        minlen = min(len1,len2,numchars)\n    else:\n        minlen = min(len1,len2)\n    #end if\n    orda = ord('a')\n    ordz = ord('z')\n\n    i = 0\n    while i &lt; minlen and 0 == result:\n        ord1 = ord(str1[i])\n        ord2 = ord(str2[i])\n        if ord1 &gt;= orda and ord1 &lt;= ordz:\n            ord1 = ord1-32\n        #end if\n        if ord2 &gt;= orda and ord2 &lt;= ordz:\n            ord2 = ord2-32\n        #end if\n        result = cmp(ord1, ord2)\n        i += 1\n    #end while\n\n    if 0 == result and minlen != numchars:\n        if len1 &lt; len2:\n            result = -1\n        elif len2 &lt; len1:\n            result = 1\n        #end if\n    #end if\n\n    return result\n#end def\n</code></pre>\n\n<p>Only use this function when it makes sense to as in many instances the lowercase technique will be superior.</p>\n\n<p>I only work with ascii strings, I'm not sure how this will behave with unicode.</p>\n"}, {'answer_id': 22249049, 'author': 'Venkatesh Bachu', 'author_id': 1008603, 'author_profile': 'https://Stackoverflow.com/users/1008603', 'pm_score': 0, 'selected': False, 'text': "<pre><code>import re\nif re.match('tEXT', 'text', re.IGNORECASE):\n    # is True\n</code></pre>\n"}]
['https://Stackoverflow.com/questions/62567', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/6984/']