web-dev-qa-db-fra.com

Chaînes mutables dans Python

S'il vous plaît, connaissez-vous une bibliothèque Python qui fournit des chaînes modifiables? Google a renvoyé étonnamment peu de résultats. La seule bibliothèque utilisable que j'ai trouvée est http://code.google.com/ p/gapbuffer / qui est en C mais je préférerais qu'il soit écrit en Python pur.

Edit: Merci pour les réponses mais je suis à la recherche d'une bibliothèque efficace . Autrement dit, ''.join(list) pourrait fonctionner mais j'espérais quelque chose de plus optimisé. De plus, il doit prendre en charge les trucs habituels que font les chaînes régulières, comme regex et unicode.

31
Ecir Hana

Dans Python le type de séquence mutable est bytearray voir ce lien

20
Jason Morgan

Cela vous permettra de changer efficacement les caractères d'une chaîne. Bien que vous ne puissiez pas changer la longueur de la chaîne.

>>> import ctypes

>>> a = 'abcdefghijklmn'
>>> mutable = ctypes.create_string_buffer(a)
>>> mutable[5:10] = ''.join( reversed(list(mutable[5:10].upper())) )
>>> a = mutable.value
>>> print `a, type(a)`
('abcdeJIHGFklmn', <type 'str'>)
19
JohnMudd
class MutableString(object):
    def __init__(self, data):
        self.data = list(data)
    def __repr__(self):
        return "".join(self.data)
    def __setitem__(self, index, value):
        self.data[index] = value
    def __getitem__(self, index):
        if type(index) == slice:
            return "".join(self.data[index])
        return self.data[index]
    def __delitem__(self, index):
        del self.data[index]
    def __add__(self, other):
        self.data.extend(list(other))
    def __len__(self):
        return len(self.data)

... et ainsi de suite.

Vous pouvez également sous-classer StringIO, buffer ou bytearray.

12
Joel Cornett

Que diriez-vous de simplement sous-classer list (le meilleur exemple de mutabilité en Python)?

class CharList(list):

    def __init__(self, s):
        list.__init__(self, s)

    @property
    def list(self):
        return list(self)

    @property
    def string(self):
        return "".join(self)

    def __setitem__(self, key, value):
        if isinstance(key, int) and len(value) != 1:
            cls = type(self).__name__
            raise ValueError("attempt to assign sequence of size {} to {} item of size 1".format(len(value), cls))
        super(CharList, self).__setitem__(key, value)

    def __str__(self):
        return self.string

    def __repr__(self):
        cls = type(self).__name__
        return "{}(\'{}\')".format(cls, self.string)

Cela joint la liste à une chaîne uniquement si vous souhaitez l'imprimer ou demander activement la représentation de la chaîne. La mutation et l'extension sont triviales, et l'utilisateur sait déjà comment le faire puisqu'il ne s'agit que d'une liste.

Exemple d'utilisation:

s = "te_st"
c = CharList(s)
c[1:3] = "oa"
c += "er"
print c # prints "toaster"
print c.list # prints ['t', 'o', 'a', 's', 't', 'e', 'r']

Ce qui suit est corrigé, voir la mise à jour ci-dessous.

Il y a une mise en garde (résoluble): Il n'y a pas (encore) de vérification que chaque élément est bien un personnage. L'impression échouera au moins pour tout sauf pour les chaînes. Cependant, ceux-ci peuvent être joints et peuvent provoquer des situations étranges comme celle-ci: [voir l'exemple de code ci-dessous]

Avec le __setitem__ Personnalisé, l'attribution d'une chaîne de longueur! = 1 à un élément CharList fera monter un ValueError. Tout le reste peut encore être librement attribué mais soulèvera un TypeError: sequence item n: expected string, X found Lors de l'impression, en raison de l'opération string.join(). Si cela ne suffit pas, d'autres vérifications peuvent être ajoutées facilement (éventuellement aussi à __setslice__ Ou en basculant la classe de base sur collections.Sequence (Les performances peuvent être différentes?!), Cf. ici )

s = "test"
c = CharList(s)
c[1] = "oa"
# with custom __setitem__ a ValueError is raised here!
# without custom __setitem__, we could go on:
c += "er"
print c # prints "toaster"
# this looks right until here, but:
print c.list # prints ['t', 'oa', 's', 't', 'e', 'r']
2
NichtJens