2016-01-06 21 views
5

İsteğe bağlı olarak ikameler uygulayarak dize varyantları üretmeye çalışıyorum. Örneğin, bir ikame şeması herhangi bir boş karakter dizisini kaldırmaktadır. yerineNormal ifadelerin birleşimsel ürünü

>>> re.sub(r'\s+', '', 'a b c') 
'abc' 

gibi tüm oluşumları değiştirilmesi dışında - I, bunun yerine, iki varyant, her bir oluşum için, üretilecek olan ihtiyaç, bu ikame ancak diğerinde, bir varyasyonda gerçekleştirilir;. dize 'a b c' için Ben varyantları

['a b c', 'a bc', 'ab c', 'abc'] 

yani

sahip olmak istiyorum. tüm ikili kararların çapraz ürünü (sonuç açıkça orijinal dizeyi içerir).

>>> list(vary('a b c', re.compile(r'\s+'), '')) 
['abc', 'ab c', 'a bc', 'a b c'] 

Ancak, bu çözüm yolu, sabit çalışır: Bu, yukarıda, örneğin, istenen çıktı üretir

def vary(target, pattern, subst): 
    occurrences = [m.span() for m in pattern.finditer(target)] 
    for path in itertools.product((True, False), repeat=len(occurrences)): 
     variant = '' 
     anchor = 0 
     for (start, end), apply_this in zip(occurrences, path): 
      if apply_this: 
       variant += target[anchor:start] + subst 
       anchor = end 
     variant += target[anchor:] 
     yield variant 

:

Bu durum için

, varyantlar re.finditer ve itertools.product kullanılarak üretilebilir -düzen değiştirmeler. grup başvuruları gibi re.sub den Gelişmiş özellikler içinde bir kelimeyi rakamlar dizisi sonra boşluk eklemek için şu örnekte olduğu gibi böyle yapılamaz: yaklaşım uzatılabilir veya değiştirilebilir nasıl

re.sub(r'\B(\d+)\B'), r'\1 ', 'abc123def') 

re.sub için geçerli bir argümanı kabul etmek (grup referanslarını yorumlamak için bir ayrıştırıcı yazmadan)?

cevap

1

olsun bu

target = 'a b c' 
pattern = re.compile(r'\s+') 
subst = '' 

print list (vary(target, pattern, subst)) 

target = 'abc123def' 
pattern = re.compile(r'\B(\d+)\B') 
subst = r'\1 ' 

print list (vary(target, pattern, subst)) 

gibi örneklerle dışarı çalışıyorum. Yani, subst ile yaklaşık bir, bu karşılık gelen eşleşmeye bount, konu dizeye atıfta olmanın tüm gerekli esnekliği kapsadığını, ben de, emin değilim bir r dize,

def vary(target, pattern, subst): 
    matches = [m for m in pattern.finditer(target)] 
    occurrences = [m.span() for m in matches] 
    for path in itertools.product((True, False), repeat=len(occurrences)): 
     variant = '' 
     anchor = 0 
     for match, (start, end), apply_this in zip(matches, occurrences, path): 
      if apply_this: 
       variant += target[anchor:start] + match.expand(subst) 
       anchor = end 
     variant += target[anchor:] 
     yield variant 

kaldıkları. Bölünmüş dizenin indekslenmiş güç kümesi akla geldi, ama sanırım bahsi geçen ayrıştırıcıdan çok uzak değil.

+1

Teşekkürler, bu çok iyi bir ipucu! Kaldırabilir bir argüman için sınırlamalar, genel durumu yaparak kolayca bırakılabilir: iç döngüde, ... + match.expand (subst) 'yi' ... + subst (match) 'ile değiştirin. Eğer argüman başlamak için callable değilse, sadece bir fonksiyona (kodun başında) sarın: 'eğer callable değilse (subst): static_subst = subst; subst = lambda m: m.expand (static_subst) – lenz

1

bu konuda nasıl: Her maç için

def vary(target, pattern, subst): 
    numOccurences = len (pattern.findall (target)) 

    for path in itertools.product((True, False), repeat=numOccurences): 

    variant  = '' 
    remainingStr = target 

    for currentFlag in path: 

     if currentFlag: 
     remainingStr = pattern.sub (subst, remainingStr, 1) 
     else: 
     currentMatch = pattern.search (remainingStr); 
     variant += remainingStr[:currentMatch.end()] 
     remainingStr = remainingStr[currentMatch.end():] 

    variant += remainingStr 

    yield variant 

, biz ya) (re.sub let (bir ikame sonra durdurmak için 1 sayısı ile beraber) işini, ya da biz uzakta değişmeden kısmı kapmak dizenin

sonunda beni yaklaşık MatchObject.expand öğrenmek yapılmış ben verileri eşleştirmek erişim alır bir çağrılabilir subst yapma düşünmek

['abc', 'ab c', 'a bc', 'a b c'] 
['abc123 def', 'abc123def'] 
+0

Öneriniz için teşekkürler. 'Re.sub' uygulanmadan önce hedef dizgenin kırpılması ile ilgili sorun, bazı köşe durumlarında gerekli içeriği kaldırmasıdır. Örneğin, 'r' \ B (\ d + | [A-Z] +) \ B '' deseni '' abc1Adef '' dizgesindeki 'A' ile eşleşir, ancak '' Adef '' kırpılmış sürümünde değil.Burada nadir vakalar seçtiğimi biliyorum, ama bu tam olarak zor takip hataları üreten durumların bir türüdür. – lenz

+0

Evet, haklısınız - bu yaklaşım tüm kötü köşeli davaları kapatmak için çok naif değildi ... – ThorngardSO