2012-04-10 16 views
9

Python dizesinde string.split() kullanırsanız, dizelerin bir listesini döndürür. Ayrılmış olan bu alt dizeler, üst dizenin kendi bölümlerinin kopyalarıdır. Dilimleri referans ile kopyalanamaz ve kopyalanamaz

yerine, sadece bir başvuru tutan ofset ve bite uzunluğu dışarı bölmek bazı ucuz dilim nesnesini almak mümkün mü?

Ve mümkündür ayıklamak ve onlar dizeleri sanki kendi bayt bir kopyasını yapmadan henüz bu alt dizeleri tedavi etmek bazı 'dize görünümü' var mı?

(Ben çok büyük dizeleri olduğu gibi ben kesmek isteyecektir ve zaman zaman bellek yetersiz çalıştırıyorum sormak;. Ucuz bir profil güdümlü kazanmak olacağını kopya kaldırma)

+0

Arabelleği() kullanan aşağıdaki yanıtlar yalnızca 2.7 için geçerlidir. memoryview(), 3.x'te normal dizeler olan unicode dizeleriyle kullanılamaz. –

cevap

17

buffer sana bir salt okunur verecek bir dizgede görüntüle.

>>> s = 'abcdefghijklmnopqrstuvwxyz' 
>>> b = buffer(s, 2, 10) 
>>> b 
<read-only buffer for 0x7f935ee75d70, size 10, offset 2 at 0x7f935ee5a8f0> 
>>> b[:] 
'cdefghijkl' 
+0

Vay, ve ben bütün yapıları bildiğimi düşünüyordum. TIL. –

+0

Bu genişletme, bu arabelleklere bölme() için standart tarifler/modüller var mı? – Will

+0

Hayır, ancak muhtemelen bunlardan birini uyarlayabilirsiniz (http://stackoverflow.com/questions/3862010/is-there-a-generator-version-of-string-split-in-python). –

1

Buraya geldiğim hızlı dize benzeri bir tampon sarıcı; Bunu, dizeleri tüketmesi beklenen kodu değiştirmeden klasik dizeler yerine kullanabildim. altdizgelerin kopyalanmalıdır böylece

class StringView: 
    def __init__(self,s,start=0,size=sys.maxint): 
     self.s, self.start, self.stop = s, start, min(start+size,len(s)) 
     self.size = self.stop - self.start 
     self._buf = buffer(s,start,self.size) 
    def find(self,sub,start=0,stop=None): 
     assert start >= 0, start 
     assert (stop is None) or (stop <= self.size), stop 
     ofs = self.s.find(sub,self.start+start,self.stop if (stop is None) else (self.start+stop)) 
     if ofs != -1: ofs -= self.start 
     return ofs 
    def split(self,sep=None,maxsplit=sys.maxint): 
     assert maxsplit > 0, maxsplit 
     ret = [] 
     if sep is None: #whitespace logic 
      pos = [self.start,self.start] # start and stop 
      def eat(whitespace=False): 
       while (pos[1] < self.stop) and (whitespace == (ord(self.s[pos[1]])<=32)): 
        pos[1] += 1 
      def eat_whitespace(): 
       eat(True) 
       pos[0] = pos[1] 
      eat_whitespace() 
      while pos[1] < self.stop: 
       eat() 
       ret.append(self.__class__(self.s,pos[0],pos[1]-pos[0])) 
       eat_whitespace() 
       if len(ret) == maxsplit: 
        ret.append(self.__class__(self.s,pos[1])) 
        break 
     else: 
      start = stop = 0 
      while len(ret) < maxsplit: 
       stop = self.find(sep,start) 
       if -1 == stop: 
        break 
       ret.append(self.__class__(self.s,self.start+start,stop-start)) 
       start = stop + len(sep) 
      ret.append(self.__class__(self.s,self.start+start,self.size-start)) 
     return ret 
    def split_str(self,sep=None,maxsplit=sys.maxint): 
     "if you really want strings and not views" 
     return [str(sub) for sub in self.split(sep,maxsplit)] 
    def __cmp__(self,s): 
     if isinstance(s,self.__class__): 
      return cmp(self._buf,s._buf) 
     assert isinstance(s,str), type(s) 
     return cmp(self._buf,s) 
    def __len__(self): 
     return self.size 
    def __str__(self): 
     return str(self._buf) 
    def __repr__(self): 
     return "'%s'"%self._buf 

if __name__=="__main__": 
    test_str = " this: is: a: te:st str:ing :" 
    test = Envelope.StringView(test_str) 
    print "find('is')" 
    print "\t",test_str.find("is") 
    print "\t",test.find("is") 
    print "find('is',4):" 
    print "\t",test_str.find("is",4) 
    print "\t",test.find("is",4) 
    print "find('is',4,7):" 
    print "\t",test_str.find("is",4,7) 
    print "\t",test.find("is",4,7) 
    print "split():" 
    print "\t",test_str.split() 
    print "\t",test.split() 
    print "split(None,2):" 
    print "\t",test_str.split(None,2) 
    print "\t",test.split(None,2) 
    print "split(':'):" 
    print "\t",test_str.split(":") 
    print "\t",test.split(":") 
    print "split('x'):" 
    print "\t",test_str.split("x") 
    print "\t",test.split("x") 
    print "''.split('x'):" 
    print "\t","".split("x") 
    print "\t",Envelope.StringView("").split("x") 
+0

Ana stanza'yı gerçek bir şey olarak bir doctest olarak yazmayı düşünmelisiniz. –

+0

32-bit bir sistemde, bu sınıfın her bir örneği, 64 bit sistemde 232 bayt bellek kullanır, daha da fazla olacaktır, bu nedenle yalnızca uzun alt dizeler için buna değecektir. En azından her bir belleğin yaklaşık yarısına kadar tüketeceği belleği azaltmak için '__slots__' kullanmalısınız. –

+0

Daha da fazla hafıza kaydetmek için, tampon nesnesinden kurtulun ya da 's',' start' ve 'stop' komutlarından kurtulun. Her halükarda, bedeninizden kurtulun. –

1

String nesneleri, her zaman, Python bir boş-sonlu tampon olduğuna işaret etmektedir. Ignacio'nun işaret ettiği gibi, dize belleğinde salt okunur bir görünüm elde etmek için buffer()'u kullanabilirsiniz. buffer() yerleşik fonksiyon Python 2.7 ve 3.x (buffer() Python 3.x gitmiş) mevcuttur olsa daha çok yönlü memoryview nesneler, yayımlandı.

s = "abcd" * 50 
view = memoryview(s) 
subview = view[10:20] 
print subview.tobytes() 

Bu kod baskılar hemen sonra tobytes() dediğimiz gibi, dize bir kopyası oluşturulacaktır

cdabcdabcd 

ancak Ignacio'nun yanıtında kadar eski buffer nesneleri dilimleme de yaşanmaktadır.

+0

evet, onun kopyaları kaçınmak için süper hevesliyim; Her zaman bir görünüm olarak kalmaya devam eden bir şeyi nasıl elde edeceğinize dair bir düşünce var mı? – Will

+0

@Will: Her ikisi de, Ignacio'nun çözümü ve bu, yalnızca arabellek/bellek görüntüsünü tutuyorsanız kopyadan kaçının. Bir dize olarak kullanmak isterseniz, geçici olarak onu bir dizeye dönüştürmeli ve üzerinde çalışmalısınız.Daha önce de söylediğim gibi, Python dizgisi arabellekleri NUL sonlandırıldı, bu yüzden bir dizenin yalnızca bir bölümünü bir dize arabelleği olarak kullanmak imkansız. –

+0

Ördek gibi daha çok iş yapmayı kastediyordum; StringView ve onun güzel çalışmasını 'in' ve yineleme ekledim. Sadece bir yerleşik değil gerçekten utanç. – Will

İlgili konular