2012-10-23 16 views
8

Bir dize şablonunun bir ikamede kullanabileceği olası tüm anahtar kelime argümanlarının bir listesini almak istiyorum.Anahtardan şablon alın

Bunu yeniden yapmanın bir yolu var mı? Ben basit Mad-lib benzeri bir program yazıyorum

text="$one is a $lonely $number." 
keys = get_keys(text) 
# keys = ('one', 'lonely', 'number') 

ve ben string.format veya Template strings biriyle şablon ikame gerçekleştirmek istiyorum:

Böyle bir şey yapmak istiyorum. 'Hikayeyi' yazmak istiyorum ve programımın bir kullanıcının üretmesi gereken 'anahtar kelimeler' (isimler, fiiller, vb.) Bir şablon dosyası üretmesini istiyorum. Bunu normal ifadelerle yapabilirim, ama alternatif bir çözüm olup olmadığını merak ediyordum? String.format ve string şablonuna alternatiflere açığım.

Bunun için bir çözüm olacağını düşündüm, ancak hızlı bir aramada rastlamadım. Bu soruyu reverse template with python buldum, ama aslında aradığım şey değil. Bu, bunun re ile yapılabileceğini tekrar doğrulamaktadır.

DÜZENLEME:

Ben $$ '$' için bir kaçış olduğunu ve istediğim bir belirteç olmadığını belirtmeliyiz. $$5, "$ 5" olarak gösterilsin.

cevap

17

kullanmayı düşünün.

+0

Neredeyse aradığım şey. Belki benim sorumun çalışması gerekiyor ama temelde tekerleği yeniden icat etmek istemedim. Teşekkürler. – Yann

+0

Dize bir anahtarla başlarsa bu çalışmaz. Yukarıdakileri, '{foo} test' ile deneyin. – syntacticmarmalade

+0

@syntacticmarmalade Python 3.6'da benim için iyi çalışıyor. Sonunda listenin bir 'Yok'un olduğu anlamına gelirse, bunun nedeni dizenin bir tuş ile * bitmemesidir. Sadece 'Yok' örneklerini filtreleyebilirsiniz. –

1

str.split() birlikte str.strip() deneyin:

In [54]: import string 

In [55]: text="$one is a $lonely $number." 

In [56]: [x.strip(string.punctuation) for x in text.split() if x.startswith("$")] 
Out[56]: ['one', 'lonely', 'number'] 
+0

** $ ** olduğunu ** string.punctuation parçası ** ** lstrip yapma (', eşleştirme grupları

>>> print string.Template.pattern.pattern \$(?: (?P<escaped>\$) | # Escape sequence of two delimiters (?P<named>[_a-z][_a-z0-9]*) | # delimiter and a Python identifier {(?P<braced>[_a-z][_a-z0-9]*)} | # delimiter and a braced identifier (?P<invalid>) # Other ill-formed delimiter exprs ) 

Ve örneğin

almak için deseni yazdırabilirsiniz $ ') ** gereksiz – volcano

+0

@volcano kontrol edildi, haklısınız. –

0

Sen deneyebilirsiniz:

def get_keys(s): 
    tokens = filter(lambda x: x[0] == "$", s.split()) 
    return map(lambda x: x[1:], tokens) 
1

Neden düzenli ifadelerden kaçınmak için istiyorsun? Onlar bunun için oldukça iyi çalışır:

>>> re.findall(r'\$[a-z]+', "$one is a $lonely $number.") 
['$one', '$lonely', '$number'] 

çiftleşmiş için re.sub check out, istediğiniz neredeyse şey yapmak için geri arama ile çağrılabilir.

>>> from string import Formatter 
>>> [i[1] for i in Formatter().parse('Hello {1} {foo}')] 
['1', 'foo'] 

fazla ayrıntı için here bakınız: o string.format kullanmanın uygun olduğu takdirde yerleşik bir parse() yöntemi vardır sınıfın string.Formatter

+0

Düzenli ifadelerden kaçınmak istemiyorum, sadece başka bir yol olup olmadığını merak ediyordum. – Yann

+0

Peki, uzun boyunlu bir Afrika hayvanı istiyorsanız, bir timsahı germek kesinlikle mümkündür, ancak çoğu durumda bir zürafa ile gitmek daha kolaydır. – che

0
>>> import string 
>>> get_keys = lambda s:[el.strip(string.punctuation) 
         for el in s.split()if el.startswith('$')] 
>>> get_keys("$one is a $lonely $number.") 
['one', 'lonely', 'number'] 
1

Sen aramaları kaydeden bir aletli sözlüğe ya da bir defaultdict ile bir kez kılmak ve daha sonra ne istedi kontrol edebilir.

from collections import defaultdict 
d = defaultdict("bogus") 
text%d 
keys = d.keys() 
5

string.Template sınıfı, bir nitelik olarak kullanır modeli vardır. Sen

>>> string.Template.pattern.findall("$one is a $lonely $number.") 
[('', 'one', '', ''), ('', 'lonely', '', ''), ('', 'number', '', '')] 
İlgili konular