2016-01-19 37 views
7

Dize nesnesinin adlandırılmış %s benzeri değişkenlerinin adlarını almanın zarif bir yolu var mı? Bunun gibi :Python dizesinden adlandırılmış değişkenlerin isimleri nasıl elde edilir

string = '%(a)s and %(b)s are friends.' 
names = get_names(string) # ['a', 'b'] 

bilinen alternatif yolları: Düzenli ifade kullanarak

  1. Ayrıştırma isimleri, ör .:

    import re 
    names = re.findall(r'%\((\w)\)[sdf]', string) # ['a', 'b'] 
    
  2. Kullanım .format() -uyumlu biçimlendirme ve Formatter().parse(string).

    How to get the variable names from the string for the format() method

Ama ne% s benzeri değişkenlerle bir dize hakkında ?

PS: piton 2.7

+2

Tanımladığınız yöntem iyi çalışıyor gibi görünüyor. ['A', 'b'] değerini döndürür. Peki şimdi ne eksik? –

+0

@AdiLevin 1 numaralı yol ilave ithalat gerektirmektedir. 2 numaralı yol başka bir dize formatı gerektirir. Sadece 'string' nesnesinin iç metot ve özelliklerini veya belki de bazı string modül fonksiyonlarını kullanarak aynı sonucu elde etmenin bir yolu olduğunu merak ediyorum. – hackprime

+0

Biçimlendirme için format() 'kullanmasını engelleyen nedir? Bu, sadece daha güçlü olduğu durumlardan biri gibi görünüyor. – Joost

cevap

0

Ayrıca yapabilirsiniz:

[y[0] for y in [x.split(')') for x in s.split('%(')] if len(y)>1] 
+0

Aynı sorudaki regex de olduğu gibi, '%% (a) s'. – BlackJack

+0

Tam gereksinim o zaman nedir? % (A) nın yanı sıra, ayrışabilmemiz için ihtiyaç duyduğumuz diğer ifadeler nelerdir? %%(gibi? Başka herhangi bir şey? –

0

Bilmiyorum bu kitabınızda gibi zarif nitelendirir, ama burada isimlerini ayrıştırır kısa fonksiyonu ise . Hata denetimi yok, bu yüzden hatalı biçimlendirilmiş biçim dizeleri için başarısız olur.

def get_names(s): 
    i = s.find('%') 
    while 0 <= i < len(s) - 3: 
     if s[i+1] == '(': 
      yield(s[i+2:s.find(')', i)]) 
     i = s.find('%', i+2) 

string = 'abd %(one) %%(two) 99 %%%(three)' 
list(get_names(string) #=> ['one', 'three'] 
0

Ayrıca, Formater solüsyonunun katılmasıyla bu % -Görev azaltabilir.

>>> import re 
>>> from string import Formatter 
>>> 
>>> string = '%(a)s and %(b)s are friends.' 
>>> 
>>> string = re.sub('((?<!%)%(\((\w)\)s))', '{\g<3>}', string) 
>>> 
>>> tuple(fn[1] for fn in Formatter().parse(string) if fn[1] is not None) 
('a', 'b') 
>>> 

Bu durumda, her iki biçimlendirmenin varyantlarını da kullanabilirsiniz.

İçindeki normal ifade, istediğiniz şeye bağlıdır. Bu soruyu yanıtlayabilmek için "zarif" tanımlamanız gerekir.

3

Göz önünde bulundurulması gereken birkaç faktör:

  1. Kod kısa mı, hatırlanması kolay, yazması kolay ve kendini açıklayıcı mı?
  2. Altta yatan mantığı yeniden kullanıyor mu (yani DRY ilkesini izleyin)?
  3. Tam olarak aynı ayrıştırma mantığını uyguluyor mu?

Maalesef, dizeler için "%" biçimlendirmesi, stringojbect.c dosyasındaki "PyString_Format" rutininde uygulanır. Bu yordam, biçim dizesinin ayrıştırılmış biçimine erişime izin veren bir API veya kanca sağlamaz. Biçim dizgisini ayrıştırırken sonucu basitçe oluşturur. Böylece herhangi bir çözümün ayrıştırma mantığını C rutininden çoğaltması gerekecektir. Bu, DRY'nin izlenmediği anlamına gelir ve biçimlendirme belirtiminde bir değişiklik yapıldığında herhangi bir çözülme ortaya çıkarır.

PyString_Format'taki ayrıştırma algoritması, anahtar adlarda iç içe parantezlerin işlenmesi de dahil olmak üzere adil bir karmaşıklık düzeyi içerir; bu nedenle, düzenli ifadeyle tam olarak uygulanamaz veya "split()" dizesi kullanılarak gerçekleştirilemez.C kodunu PyString_Format'tan kopyalayıp Python koduna dönüştürmenin kısa bir yolu, tüm koşullarında eşleme anahtarlarının adlarını doğru bir şekilde çıkarmanın herhangi bir kolay yolunu görmüyorum.

Sonuç olarak, bir Python 2.7 "%" biçim dizesi için eşleme anahtarlarının adlarını almak için "zarif" bir yol yoktur.

import re 
class StringFormattingParser(object): 
    __matcher = re.compile(r'(?<!%)%\(([^)]+)\)[-# +0-9.hlL]*[diouxXeEfFgGcrs]') 
    @classmethod 
    def getKeyNames(klass, formatString): 
     return klass.__matcher.findall(formatString) 

# Demonstration of use with some sample format strings 
for value in [ 
    '%(a)s and %(b)s are friends.', 
    '%%(nomatch)i', 
    '%%', 
    'Another %(matched)+4.5f%d%% example', 
    '(%(should_match(but does not))s', 
    ]: 
    print StringFormattingParser.getKeyNames(value) 

# Note the following prints out "really does match"! 
print '%(should_match(but does not))s' % {'should_match(but does not)': 'really does match'} 

dip not:

Aşağıdaki kod en yaygın kullanımını kapsayan kısmi bir çözüm temin etmek üzere normal bir ifade kullanır DRY = Kendini Tekrar Etme (https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)