Assuming ASCII strings:
string1 = 'Hello'
string2 = 'hello'
if string1.lower() == string2.lower():
print("The strings are the same (case insensitive)")
else:
print("The strings are NOT the same (case insensitive)")
As of Python 3.3, casefold() is a better alternative:
string1 = 'Hello'
string2 = 'hello'
if string1.casefold() == string2.casefold():
print("The strings are the same (case insensitive)")
else:
print("The strings are NOT the same (case insensitive)")
If you want a more comprehensive solution that handles more complex unicode comparisons, see other answers.
Answer from Harley Holcombe on Stack OverflowAssuming ASCII strings:
string1 = 'Hello'
string2 = 'hello'
if string1.lower() == string2.lower():
print("The strings are the same (case insensitive)")
else:
print("The strings are NOT the same (case insensitive)")
As of Python 3.3, casefold() is a better alternative:
string1 = 'Hello'
string2 = 'hello'
if string1.casefold() == string2.casefold():
print("The strings are the same (case insensitive)")
else:
print("The strings are NOT the same (case insensitive)")
If you want a more comprehensive solution that handles more complex unicode comparisons, see other answers.
Comparing strings in a case insensitive way seems trivial, but it's not. I will be using Python 3, since Python 2 is underdeveloped here.
The first thing to note is that case-removing conversions in Unicode aren't trivial. There is text for which text.lower() != text.upper().lower(), such as "ß":
>>> "ß".lower()
'ß'
>>> "ß".upper().lower()
'ss'
But let's say you wanted to caselessly compare "BUSSE" and "Buße". Heck, you probably also want to compare "BUSSE" and "BUẞE" equal - that's the newer capital form. The recommended way is to use casefold:
str.casefold()
Return a casefolded copy of the string. Casefolded strings may be used for caseless matching.
Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string. [...]
Do not just use lower. If casefold is not available, doing .upper().lower() helps (but only somewhat).
Then you should consider accents. If your font renderer is good, you probably think "ê" == "ê" - but it doesn't:
>>> "ê" == "ê"
False
This is because the accent on the latter is a combining character.
>>> import unicodedata
>>> [unicodedata.name(char) for char in "ê"]
['LATIN SMALL LETTER E WITH CIRCUMFLEX']
>>> [unicodedata.name(char) for char in "ê"]
['LATIN SMALL LETTER E', 'COMBINING CIRCUMFLEX ACCENT']
The simplest way to deal with this is unicodedata.normalize. You probably want to use NFKD normalization, but feel free to check the documentation. Then one does
>>> unicodedata.normalize("NFKD", "ê") == unicodedata.normalize("NFKD", "ê")
True
To finish up, here this is expressed in functions:
import unicodedata
def normalize_caseless(text):
return unicodedata.normalize("NFKD", text.casefold())
def caseless_equal(left, right):
return normalize_caseless(left) == normalize_caseless(right)
Python : How to compare strings and ignore white space and special characters - Stack Overflow
How to compare string and ignore white space and cases?
performance - Comparing strings, ignoring case, punctuation, and whitespace - Code Review Stack Exchange
bash - How to do a string comparison ignore whitespace? - Unix & Linux Stack Exchange
Is Python string comparison case sensitive?
How do you compare strings ignoring case in Python?
How do you check if a substring exists in a string in Python?
This removes punctuation and whitespace before doing the comparison:
In [32]: import string
In [33]: def compare(s1, s2):
...: remove = string.punctuation + string.whitespace
...: return s1.translate(None, remove) == s2.translate(None, remove)
In [34]: compare('Hai, this is a test', 'Hai ! this is a test')
Out[34]: True
>>> def cmp(a, b):
... return [c for c in a if c.isalpha()] == [c for c in b if c.isalpha()]
...
>>> cmp('Hai, this is a test', 'Hai ! this is a test')
True
>>> cmp('Hai, this is a test', 'Hai this is a test')
True
>>> cmp('Hai, this is a test', 'other string')
False
This creates two temporary lists, but doesn't modify the original strings in any way.
You might want to create a combined CharacterSet of punctuation and whitespace first and then apply this set using a single operation. This should speed things up. Please have a look at this code snippet:
let punctuation = CharacterSet.punctuationCharacters
let whitespace = CharacterSet.whitespaces
let unwanted = punctuation.union(whitespace)
let components = filterString.components(separatedBy: unwanted).joined(" ")
let filterStringContainsSearchText = components.contains(searchText)
Optimizing your search will require that you don't repeat costly operations on every item if they can be performed once beforehand.
It would also help to avoid the overhead of special character processing if the search text doesn't justify it (e.g if it has no spaces or special characters itself).
Finally, procedural code (for loops) are optimized more efficiently by the compiler than their "functional" equivalent (.filter / .map) so the traversal of songs should be performed in a loop instead of a .filter()
I would suggest extending the MPMediaQuery class to allow it to provide a filtered list of songs in the most optimal way possible. This has some reuse value and will keep your main logic more readable and maintainable.
On the other hand, if the MPMediaQuery goes back to storage every time, it will be more efficient to create a simple function that takes the array of songs as a parameter.
For example:
extension MPMediaQuery
{
static func songsMatching(_ searchText:String) -> [MPMediaItem]
{
// Common function to turn special characters into spaces
// will have a certain amount of overhead so we will try
// to avoid using it if possible...
func normalizedText(_ text:String) -> String
{
let chars = text.unicodeScalars.enumerated()
.map ({
CharacterSet.punctuationCharacters.contains($1)
|| CharacterSet.whitespaces.contains($1)
? " " : Character($1)
})
return String(chars)
}
// Search string should only be prepared once
// This means that the whole filtering operation needs to be
// included in the optimization.
let searchString = searchText.lowercased()
let cleanedString = normalizedText(searchString)
// based on search string content, we can forgo complex comparisons
// We only need to manage special characters if the search text
// contains any.
// If the search text doesn't contain spaces or special characters
// then removing them from the titles is unnecessary
let simpleFilter = !cleanedString.contains(" ")
// The Swift optimizer is much more efficient compiling procedural
// code (As opposed to the functional style .filter{} and such)
// This can give a 20x speed boost in some cases.
var result:[MPMediaItem] = []
for song in songs().items ?? []
{
guard let title = song.title?.lowercased()
else { continue }
if simpleFilter
{
if title.contains(searchString)
{ result.append(song) }
}
else
{
if normalizedText(title).contains(searchString)
{ result.append(song) }
}
}
return result
}
}
Technically, to ignore all whitespace you could pass both strings through tr:
[ "$(echo "$a" | tr -d '[:space:]')" = "$(echo "$b" | tr -d '[:space:]')" ]
However, this way all whitespace gets removed before the comparison, so for example "a b" and "ab" will test equal. I'm not sure this is desirable. You can tweak the tr filter to do what you need. For instance, to remove only newlines of all flavours, you can do tr -d '\n\r'.
In bash, you can use a parameter expansion syntax to take the value of a variable with some characters removed (or more generally replacing occurrences of a pattern).
if [[ "${a//[$' \t\n\r']/}" == "${b//[$' \t\n\r']/}" ]]; then
echo ok
fi
If the problem is that they're “using different newline characters”, that probably means that one of them is coming from a Windows file. Windows lines have an extra CR (carriage return, $'\r in bash syntax) before the newline character ($'\n'). If you have multiline strings, you can strip off just the CR characters:
if [[ "${a//$'\r'/}" == "${b//$'\r'/}" ]]; then
echo ok
fi
If the variables are single-line strings then the troublesome CR would be at the end and you can use the suffix stripping syntax:
if [[ "${a%$'\r'}" == "${b%$'\r'}" ]]; then
echo ok
fi
If you need this one in plain sh, the (minor) difficulty is entering a CR character.
cr=$(printf '\r')
if [[ "${a%$cr}" == "${b%$cr}" ]]; then
echo ok
fi
Hi! mega mega noob, literally first day of bash and I am struggling any help would be appreciated!!
I need to compare two strings and find whether string A exists as a substring of string B. The comparison needs to ignore case and ignore whitespace.
String A is saved in a txt file (ex: test.txt).
String B is the output of a file that used some input, I have literally no clue in what format the output exists but this is the line that creates the variable (output should be the console output of a program that is run with the pre-set input):
java "$(find *.java | sed 's/\.java$//1')" < input > output
So I need to find whether the text in test.txt exists as a substring of the output string, ignoring case and ignoring all horizontal and vertical whitespace (not just edge whitespace).
I've tried varieties of diff, tr, and if statements using =~ and ** but nothing is working and I really don't know enough to troubleshoot...help?
You can create a new string that has the properties you want, and then compare with the new string(s). This will strip everything but numbers, letters, and spaces while making all letters lowercase.
''.join([letter.lower() for letter in ' '.join(words) if letter.isalnum() or letter == ' '])
To strip everything but letters from a string you can do something like:
from string import ascii_letters
''.join([letter for letter in word if letter in ascii_letters])
You could use a regex:
import re
st="Money is the last money."
words=st.split()
beats=['money','nonsense']
for i,word in enumerate(words):
if word=='match': continue
for tgt in beats:
word=re.sub(r'\b{}\b'.format(tgt),'match',word,flags=re.I)
words[i]=word
print print ' '.join(words)
prints
match is the last match.
So I have a script which replaces a set of strings in a text file, but it needs to be case sensitive, is this a built in function or do I need to do some black magic