Ich möchte, dass in meinem Wörterbuch die Groß- und Kleinschreibung nicht berücksichtigt wird.
Ich habe diesen Beispielcode:
text = "practice changing the color"
words = {'color': 'colour',
'practice': 'practise'}
def replace(words,text):
keys = words.keys()
for i in keys:
text= text.replace(i ,words[i])
return text
text = replace(words,text)
print text
Ausgabe = üben, die Farbe zu ändern
Ich möchte, dass eine andere Zeichenfolge "practice changing the Color"
(wobei Color
mit einem Großbuchstaben beginnt) dieselbe Ausgabe liefert.
Ich glaube, es gibt eine allgemeine Möglichkeit, mit Kleinbuchstaben zu konvertieren,
mydictionary[key.lower()]
aber ich bin mir nicht sicher, wie ich dies am besten in meinen vorhandenen Code integrieren kann. (Wenn dies sowieso ein vernünftiger, einfacher Ansatz wäre).
collections.TransformDict
vorausgesetzt, die Transformation iststr.casefold
ähnlich oder ähnlich)Antworten:
Wenn ich Sie richtig verstehe und Sie eine Möglichkeit suchen, Wörterbücher ohne Berücksichtigung der Groß- und Kleinschreibung zu verwenden, besteht eine Möglichkeit darin, den Setter / Getter in Unterklassen zu diktieren und zu überladen:
class CaseInsensitiveDict(dict): def __setitem__(self, key, value): super(CaseInsensitiveDict, self).__setitem__(key.lower(), value) def __getitem__(self, key): return super(CaseInsensitiveDict, self).__getitem__(key.lower())
quelle
__contains__, get, and has_key
zur Antwort hinzugefügt , seit ich sie codiert habe :)dict
. Verwenden Sie es nicht in Ihrem Code - es bricht alle außer den einfachsten Verwendungen. Anscheinend hat @MichaelMerchant versucht, das fehlende Material hinzuzufügen, aber die Moderation hat die Änderungen abgelehnt (dasselbe ist mir passiert). Ich habe eine neue Antwort hinzugefügt, die hier alsdict
Ersatz verwendet werden sollte .UserDict
als Unterklassen alsdict
docs.python.org/3.5/library/collections.html#userdict-objectsDie derzeit genehmigte Antwort funktioniert in vielen Fällen nicht und kann daher nicht als
dict
Ersatz verwendet werden. Einige knifflige Punkte bei der Suche nach einem geeignetendict
Ersatz:Folgendes sollte viel besser funktionieren:
class CaseInsensitiveDict(dict): @classmethod def _k(cls, key): return key.lower() if isinstance(key, basestring) else key def __init__(self, *args, **kwargs): super(CaseInsensitiveDict, self).__init__(*args, **kwargs) self._convert_keys() def __getitem__(self, key): return super(CaseInsensitiveDict, self).__getitem__(self.__class__._k(key)) def __setitem__(self, key, value): super(CaseInsensitiveDict, self).__setitem__(self.__class__._k(key), value) def __delitem__(self, key): return super(CaseInsensitiveDict, self).__delitem__(self.__class__._k(key)) def __contains__(self, key): return super(CaseInsensitiveDict, self).__contains__(self.__class__._k(key)) def has_key(self, key): return super(CaseInsensitiveDict, self).has_key(self.__class__._k(key)) def pop(self, key, *args, **kwargs): return super(CaseInsensitiveDict, self).pop(self.__class__._k(key), *args, **kwargs) def get(self, key, *args, **kwargs): return super(CaseInsensitiveDict, self).get(self.__class__._k(key), *args, **kwargs) def setdefault(self, key, *args, **kwargs): return super(CaseInsensitiveDict, self).setdefault(self.__class__._k(key), *args, **kwargs) def update(self, E={}, **F): super(CaseInsensitiveDict, self).update(self.__class__(E)) super(CaseInsensitiveDict, self).update(self.__class__(**F)) def _convert_keys(self): for k in list(self.keys()): v = super(CaseInsensitiveDict, self).pop(k) self.__setitem__(k, v)
quelle
update
istupdate(self, E=None, **F)
, was bedeutet,E
ist optional. Sie haben es neu definiert, um esE
erforderlich zu machen . Fügen Sie in=None
und das wird perfekt sein.basestring
entfernt.str
kann als Ersatz verwendet werden.Nur für das Protokoll. Ich habe eine großartige Umsetzung bei Anfragen gefunden :
https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37
quelle
from requests.structures import CaseInsensitiveDict
In meinem speziellen Fall benötigte ich eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung, wollte jedoch den ursprünglichen Fall des Schlüssels nicht ändern. Zum Beispiel:
>>> d = {} >>> d['MyConfig'] = 'value' >>> d['myconfig'] = 'new_value' >>> d {'MyConfig': 'new_value'}
Sie können sehen, dass das Wörterbuch immer noch den Originalschlüssel enthält, jedoch ohne Berücksichtigung der Groß- und Kleinschreibung. Hier ist eine einfache Lösung:
class CaseInsensitiveKey(object): def __init__(self, key): self.key = key def __hash__(self): return hash(self.key.lower()) def __eq__(self, other): return self.key.lower() == other.key.lower() def __str__(self): return self.key
Die Überschreibungen __hash__ und __eq__ sind erforderlich, um Einträge im Wörterbuch abzurufen und festzulegen. Dadurch werden Schlüssel erstellt, die an derselben Position im Wörterbuch gehasht werden, wenn die Groß- und Kleinschreibung nicht berücksichtigt wird.
Erstellen Sie nun entweder ein benutzerdefiniertes Wörterbuch, das einen CaseInsensitiveKey mit dem angegebenen Schlüssel initialisiert:
class CaseInsensitiveDict(dict): def __setitem__(self, key, value): key = CaseInsensitiveKey(key) super(CaseInsensitiveDict, self).__setitem__(key, value) def __getitem__(self, key): key = CaseInsensitiveKey(key) return super(CaseInsensitiveDict, self).__getitem__(key)
oder stellen Sie einfach sicher, dass Sie bei Verwendung des Wörterbuchs immer eine Instanz von CaseInsensitiveKey als Schlüssel übergeben.
quelle
.casefold()
statt.lower()
für Vergleiche verwenden,self.key.casefold() == other.key.casefold()
um unter anderem zuzulassen"ß"
und"ss"
als wahr gleichzusetzen.Würden Sie in Betracht ziehen,
string.lower()
Ihre Eingaben zu verwenden und ein vollständig klein geschriebenes Wörterbuch zu verwenden? Es ist ein bisschen eine hackige Lösung, aber es funktioniertquelle
Ich habe die einfache, aber gute Lösung durch Pleasemorebacon (danke!) Modifiziert , um sie etwas kompakter, eigenständiger und mit geringfügigen Aktualisierungen zu gestalten, damit das Protokoll erstellt
{'a':1, 'B':2}
und unterstützt werden__contains__
kann. Schließlich, da dieCaseInsensitiveDict.Key
auf sein String erwartet (was sonst Fall empfindlich sein kann oder nicht), ist es eine gute Idee , herzuleitenKey
Klasse aus demstr
, so ist es möglich, zum Beispiel, DumpCaseInsensitiveDict
mitjson.dumps
aus dem Kasten heraus .# caseinsensitivedict.py class CaseInsensitiveDict(dict): class Key(str): def __init__(self, key): str.__init__(key) def __hash__(self): return hash(self.lower()) def __eq__(self, other): return self.lower() == other.lower() def __init__(self, data=None): super(CaseInsensitiveDict, self).__init__() if data is None: data = {} for key, val in data.items(): self[key] = val def __contains__(self, key): key = self.Key(key) return super(CaseInsensitiveDict, self).__contains__(key) def __setitem__(self, key, value): key = self.Key(key) super(CaseInsensitiveDict, self).__setitem__(key, value) def __getitem__(self, key): key = self.Key(key) return super(CaseInsensitiveDict, self).__getitem__(key)
Hier ist ein grundlegendes Testskript für diejenigen, die Dinge in Aktion überprüfen möchten:
# test_CaseInsensitiveDict.py import json import unittest from caseinsensitivedict import * class Key(unittest.TestCase): def setUp(self): self.Key = CaseInsensitiveDict.Key self.lower = self.Key('a') self.upper = self.Key('A') def test_eq(self): self.assertEqual(self.lower, self.upper) def test_hash(self): self.assertEqual(hash(self.lower), hash(self.upper)) def test_str(self): self.assertEqual(str(self.lower), 'a') self.assertEqual(str(self.upper), 'A') class Dict(unittest.TestCase): def setUp(self): self.Dict = CaseInsensitiveDict self.d1 = self.Dict() self.d2 = self.Dict() self.d1['a'] = 1 self.d1['B'] = 2 self.d2['A'] = 1 self.d2['b'] = 2 def test_contains(self): self.assertIn('B', self.d1) d = self.Dict({'a':1, 'B':2}) self.assertIn('b', d) def test_init(self): d = self.Dict() self.assertFalse(d) d = self.Dict({'a':1, 'B':2}) self.assertTrue(d) def test_items(self): self.assertDictEqual(self.d1, self.d2) self.assertEqual( [v for v in self.d1.items()], [v for v in self.d2.items()]) def test_json_dumps(self): s = json.dumps(self.d1) self.assertIn('a', s) self.assertIn('B', s) def test_keys(self): self.assertEqual(self.d1.keys(), self.d2.keys()) def test_values(self): self.assertEqual( [v for v in self.d1.values()], [v for v in self.d2.values()])
quelle
.casefold()
statt.lower()
für Vergleiche verwendenself.casefold() == other.key.casefold()
undhash(self.casefold())
unter anderem "ß" und "ss" als wahr gleichsetzen.Während ein Wörterbuch ohne Berücksichtigung der Groß- und Kleinschreibung eine Lösung darstellt und es Antworten gibt, wie dies erreicht werden kann, gibt es in diesem Fall möglicherweise einen einfacheren Weg. Eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung ist ausreichend:
import re text = "Practice changing the Color" words = {'color': 'colour', 'practice': 'practise'} def replace(words,text): keys = words.keys() for i in keys: exp = re.compile(i, re.I) text = re.sub(exp, words[i], text) return text text = replace(words,text) print text
quelle
Sie können mit einem Einzeiler eine Suche ohne Groß- und Kleinschreibung durchführen.
>>> input_dict = {'aBc':1, 'xyZ':2} >>> search_string = 'ABC' >>> next((value for key, value in input_dict.items() if key.lower()==search_string.lower()), None) 1 >>> search_string = 'EFG' >>> next((value for key, value in input_dict.items() if key.lower()==search_string.lower()), None) >>>
Sie können das in eine Funktion einfügen:
def get_case_insensitive_key_value(input_dict, key): return next((value for dict_key, value in input_dict.items() if dict_key.lower() == key.lower()), None)
Beachten Sie, dass nur die erste Übereinstimmung zurückgegeben wird.
quelle
Wenn Sie dies nur einmal in Ihrem Code tun müssen (daher kein Hinweis auf eine Funktion), ist der einfachste Weg, um das Problem zu lösen, folgender:
Kleinbuchstaben_dict = {key.lower (): Wert für (Schlüssel, Wert) in original_dict}
Ich gehe hier davon aus, dass das fragliche Diktat nicht allzu groß ist - es mag unelegant sein, es zu duplizieren, aber wenn es nicht groß ist, wird es nichts schaden.
Der Vorteil gegenüber der Antwort von @ Fred (obwohl das auch funktioniert) ist, dass es das gleiche Ergebnis wie ein Diktat erzeugt, wenn der Schlüssel nicht vorhanden ist: ein KeyError.
quelle
Ich habe gerade eine Funktion eingerichtet, um dies zu handhaben:
def setLCdict(d, k, v): k = k.lower() d[k] = v return d myDict = {}
Also statt
myDict['A'] = 1 myDict['B'] = 2
Sie können:
myDict = setLCdict(myDict, 'A', 1) myDict = setLCdict(myDict, 'B', 2)
Sie können den Wert dann entweder vor dem Nachschlagen in Kleinbuchstaben schreiben oder eine entsprechende Funktion schreiben.
def lookupLCdict(d, k): k = k.lower() return d[k] myVal = lookupLCdict(myDict, 'a')
Wahrscheinlich nicht ideal, wenn Sie dies global tun möchten, aber es funktioniert gut, wenn es nur eine Teilmenge ist, für die Sie es verwenden möchten.
quelle