Hoe kan ik hoofdletterongevoelige tekenreeksen vergelijken in Python?
Ik wil graag de vergelijking van een reguliere string met een repository-string op een zeer eenvoudige en Pythonische manier inkapselen. Ik zou ook graag de mogelijkheid willen hebben om waarden op te zoeken in een dictaat dat is gehasht door strings met behulp van gewone python-strings.
Antwoord 1, autoriteit 100%
Ervan uitgaande dat ASCII-tekenreeksen:
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)")
Antwoord 2, autoriteit 94%
Het vergelijken van strings op een niet-hoofdlettergevoelige manier lijkt triviaal, maar is het niet. Ik zal Python 3 gebruiken, omdat Python 2 hier onderontwikkeld is.
Het eerste dat moet worden opgemerkt, is dat het verwijderen van hoofdletters in Unicode niet triviaal is. Er is tekst waarvoor text.lower() != text.upper().lower()
, zoals "?"
:
"?".lower()
#>>> '?'
"?".upper().lower()
#>>> 'ss'
Maar laten we zeggen dat je "BUSSE"
en "BU?E"
zonder hoofdletters wilt vergelijken. Heck, je wilt waarschijnlijk ook "BUSSE"
en "BU?E"
gelijk vergelijken – dat is de nieuwere hoofdletter. De aanbevolen manier is om casefold
:
str.casefold()
Retourneer een opgevouwen kopie van de tekenreeks. Casefolded snaren kunnen worden gebruikt voor:
matchen zonder hoofdletters.Casefolding lijkt op kleine letters, maar is agressiever omdat het dat is
bedoeld om alle onderscheidingen tussen hoofdletters in een string te verwijderen. […]
Gebruik niet alleen lower
. Als casefold
niet beschikbaar is, helpt het om .upper().lower()
te doen (maar slechts in beperkte mate).
Dan moet je rekening houden met accenten. Als uw lettertype-renderer goed is, denkt u waarschijnlijk "e" == "e?"
– maar dat is niet zo:
"e" == "e?"
#>>> False
Dit komt omdat het accent op de laatste een combinatiekarakter is.
import unicodedata
[unicodedata.name(char) for char in "e"]
#>>> ['LATIN SMALL LETTER E WITH CIRCUMFLEX']
[unicodedata.name(char) for char in "e?"]
#>>> ['LATIN SMALL LETTER E', 'COMBINING CIRCUMFLEX ACCENT']
De eenvoudigste manier om hiermee om te gaan is unicodedata.normalize
. Je wilt waarschijnlijk NFKDnormalisatiegebruiken, maar voel je vrij om de documentatie te controleren. Dan doet men dat wel
unicodedata.normalize("NFKD", "e") == unicodedata.normalize("NFKD", "e?")
#>>> True
Om af te ronden, hier wordt dit uitgedrukt in functies:
import unicodedata
def normalize_caseless(text):
return unicodedata.normalize("NFKD", text.casefold())
def caseless_equal(left, right):
return normalize_caseless(left) == normalize_caseless(right)
Antwoord 3, autoriteit 10%
Python 2 gebruiken, .lower()
aanroepen voor elke string of Unicode-object…
string1.lower() == string2.lower()
…zal meestal werken, maar werkt inderdaad niet in de situaties die @tchrist heeft beschreven.
Stel dat we een bestand hebben met de naam unicode.txt
met daarin de twee strings ???????
en ???????
. Met Python 2:
>>> utf8_bytes = open("unicode.txt", 'r').read()
>>> print repr(utf8_bytes)
'\xce\xa3\xce\xaf\xcf\x83\xcf\x85\xcf\x86\xce\xbf\xcf\x82\n\xce\xa3\xce\x8a\xce\xa3\xce\xa5\xce\xa6\xce\x9f\xce\xa3\n'
>>> u = utf8_bytes.decode('utf8')
>>> print u
???????
???????
>>> first, second = u.splitlines()
>>> print first.lower()
???????
>>> print second.lower()
???????
>>> first.lower() == second.lower()
False
>>> first.upper() == second.upper()
True
De ? karakter heeft twee kleine letters, ? en ?, en .lower()
helpen niet om ze hoofdletterongevoelig te vergelijken.
Vanaf Python 3 zullen echter alle drie de vormen worden omgezet in ?, en het aanroepen van lower() op beide strings zal correct werken:
>>> s = open('unicode.txt', encoding='utf8').read()
>>> print(s)
???????
???????
>>> first, second = s.splitlines()
>>> print(first.lower())
???????
>>> print(second.lower())
???????
>>> first.lower() == second.lower()
True
>>> first.upper() == second.upper()
True
Dus als je om randgevallen geeft, zoals de drie sigma’s in het Grieks, gebruik dan Python 3.
(Ter referentie, Python 2.7.3 en Python 3.3.0b1 worden getoond in de tolk-afdrukken hierboven.)
Antwoord 4, autoriteit 7%
Sectie 3.13 van de Unicode-standaarddefinieert algoritmen voor
overeenkomend.
X.casefold() == Y.casefold()
in Python 3 implementeert de “standaard caseless matching” (D144).
Casefolding behoudt de normalisatie van strings niet in alle gevallen en daarom moet de normalisatie worden uitgevoerd ('a'
vs. 'a?'
). D145 introduceert “canonieke matching zonder hoofdletters”:
import unicodedata
def NFD(text):
return unicodedata.normalize('NFD', text)
def canonical_caseless(text):
return NFD(NFD(text).casefold())
NFD()
wordt twee keer aangeroepen voor zeer zeldzame randgevallen met U+0345-tekens.
Voorbeeld:
>>> 'a'.casefold() == 'a?'.casefold()
False
>>> canonical_caseless('a') == canonical_caseless('a?')
True
Er zijn ook compatibiliteitsvergelijkingen zonder hoofdletters (D146) voor gevallen zoals '?'
(U+3392) en “identificatieletters zonder hoofdletters” om identificatie zonder hoofdletters.
Antwoord 5
Ik zag deze oplossing hier met behulp van regex.
import re
if re.search('mandy', 'Mandy Pande', re.IGNORECASE):
# is True
Het werkt goed met accenten
In [42]: if re.search("e","e", re.IGNORECASE):
....: print(1)
....:
1
Het werkt echter niet met unicode-tekens die niet hoofdlettergevoelig zijn. Bedankt @Rhymoid om erop te wijzen dat, zoals ik begreep, het exacte symbool nodig is om de zaak waar te maken. De uitvoer is als volgt:
In [36]: "?".lower()
Out[36]: '?'
In [37]: "?".upper()
Out[37]: 'SS'
In [38]: "?".upper().lower()
Out[38]: 'ss'
In [39]: if re.search("?","??", re.IGNORECASE):
....: print(1)
....:
1
In [40]: if re.search("SS","??", re.IGNORECASE):
....: print(1)
....:
In [41]: if re.search("?","SS", re.IGNORECASE):
....: print(1)
....:
Antwoord 6
U kunt de methode casefold() gebruiken. De methode casefold() negeert gevallen bij het vergelijken.
firstString = "Hi EVERYONE"
secondString = "Hi everyone"
if firstString.casefold() == secondString.casefold():
print('The strings are equal.')
else:
print('The strings are not equal.')
Uitvoer:
The strings are equal.
Antwoord 7
De gebruikelijke aanpak is om de tekenreeksen in hoofdletters of in kleine letters te gebruiken voor het opzoeken en vergelijken. Bijvoorbeeld:
>>> "hello".upper() == "HELLO".upper()
True
>>>
Antwoord 8
Wat dacht je ervan om eerst naar kleine letters te converteren? je kunt string.lower()
gebruiken.
Antwoord 9
U kunt case=Falsevermelden in de str.contains()
data['Column_name'].str.contains('abcd', case=False)
Antwoord 10
def insenStringCompare(s1, s2):
""" Method that takes two strings and returns True or False, based
on if they are equal, regardless of case."""
try:
return s1.lower() == s2.lower()
except AttributeError:
print "Please only pass strings into this method."
print "You passed a %s and %s" % (s1.__class__, s2.__class__)
Antwoord 11
Dit is een andere regex die ik de afgelopen week heb leren liefhebben / haten, dus importeer ze meestal als (in dit geval ja) iets dat weerspiegelt hoe ik me voel!
maak een normale functie…. vraag om invoer, gebruik dan ….something = re.compile(r’foo*|spam*’, yes.I)…… re.I (yes.I hieronder) is hetzelfde als IGNORECASE, maar je kunt niet zoveel fouten maken als je het schrijft!
Je doorzoekt dan je bericht met behulp van regex’s, maar eerlijk gezegd zou dat een paar pagina’s op zich moeten zijn, maar het punt is dat foo of spam samen worden doorgesluisd en hoofdletters worden genegeerd.
Als een van beide wordt gevonden, zal lost_n_found er een weergeven. indien geen van beide, dan is lost_n_found gelijk aan Geen. Als het niet gelijk is aan geen, retourneer je de user_input in kleine letters met “return lost_n_found.lower()”
Hierdoor kunt u veel gemakkelijker alles matchen dat hoofdlettergevoelig is. Ten slotte staat (NCS) voor “no one cares serious…!” of niet hoofdlettergevoelig….wat dan ook
Als iemand vragen heeft, laat het me weten..
import re as yes
def bar_or_spam():
message = raw_input("\nEnter FoO for BaR or SpaM for EgGs (NCS): ")
message_in_coconut = yes.compile(r'foo*|spam*', yes.I)
lost_n_found = message_in_coconut.search(message).group()
if lost_n_found != None:
return lost_n_found.lower()
else:
print ("Make tea not love")
return
whatz_for_breakfast = bar_or_spam()
if whatz_for_breakfast == foo:
print ("BaR")
elif whatz_for_breakfast == spam:
print ("EgGs")