% S nasıl {0}, {1}… daha az karmaşık?


11

Ben daha sonra yerine koymak için yer tutucular içeren bir dize almak zorunda, gibi:

"A %s B %s"

Ve bunu şuna dönüştürün:

"A {0} B {1}"

Ben geldim:

def _fix_substitution_parms(raw_message):
  rv = raw_message
  counter = 0
  while '%s' in rv:
    rv = rv.replace('%s', '{' + str(counter) + '}', 1)
    counter = counter + 1
return rv

Bu işe yarıyor, ama süper tıknaz ve hiç de "deyimsel" python hissetmiyor.

İyi, deyimsel bir python çözümü nasıl görünürdü?

Açıklama için güncellemeler:

  • elde edilen dizeler python içinde kullanılmaz. Ben bunu orada sayaç numaraları gerekiyor! (yani {}yeterince iyi değil)!
  • %sMesajların sadece kullanımı garanti edildiği için sadece dizeleri önemsemem gerekiyor %s(hiçbir %i %fşekilde)

"re.sub", dinamik olarak numaralandırılmış parantezlerle değiştirmek için bir işlev alabilir. Bu arada: {} ile numaralar olmadan değiştirmek de işe yarayacaktır.
Michael Butscher

3
Çalışan bir çözümünüz olduğunda ve bunu geliştirmek istediğinizde, lütfen codereview.stackexchange.com'u düşünün
Kojiro

@kojiro "Çok tıknaz" ;-) nedeniyle benim için çalışmıyor
GhostCat Monica C. selamlıyor

Yanıtlar:


5

Ben Reznik ne yapardın aslen önerdi ve sonra çağrı .formatbu konuda:

def _fix_substitution_parms(raw_message: str) -> str:
    num_to_replace = raw_message.count("%s")
    python_format_string_message = raw_message.replace("%s", "{{{}}}")
    final_message = python_format_string_message.format(*range(num_to_replace))
    return final_message

bu sadece %smetinde 2 varsa çalışır ?
Charif DZ

@CharifDZ ve Aran-Fey - düzenlemeye bakın. Onları elden önce
Dan

İyi bir uzlaşma gibi görünüyor ... okunabilir, ama çok süslü değil.
GhostCat Monica C.'yi selamlıyor

8

re.subHer eleman için ikameyi bir kez daha uygulamak ve itertools.countsıralı olarak sayı almak için lambda işleviyle kullanın :

import itertools
import re

s = "A %s B %s"

counter = itertools.count()
result = re.sub('%s', lambda x: f'{{{next(counter)}}}', s)
print(result)  # 'A {0} B {1}'

Yenilemeniz gerekeceğinden, bu işlemi bir kereden fazla gerçekleştirmek için bir işleve sarmayı unutmayın itertools.count.


Güzel, biraz "belirsiz" ;-) olsa da
GhostCat Monica C. selamlıyor

@GhostCat karanlık değil, sayaç bir next(counter)sonraki değeri üretmek dediğinde bir jeneratör , her zaman bu jeneratör gerçekten güzel bir cevap unutuyorum
Charif DZ

@GhostCat regex ve aynı satırda fonksiyonel programlama: -PI "belirsiz" tahmin bu araçlar için ne kadar kullandığınıza bağlıdır.
jfaccioni

3

Bence bu şut çalışması

rv.replace('%s','{{{}}}').format(*range(rv.count('%s')))


1
@GhostCat bir gömlek tarafından cazip değil, insanların kodunu korumak zorunda olduğunu unutmayın
Dan

1
@Biliyorum. Ama daha az kod da korumak için daha az kod.
GhostCat Monica C.'yi selamlıyor

Yine de daha az değil, hata ayıklamak ve gelecekteki bir geliştiriciye okumak daha zor. Bu cevap benimkine benzemeye oldukça yakın, aynı işlev çağrılarına sahip (bölünme ve katılma için değiştirmeyi değiştiriyor), ancak bir ara adımda bir sorun varsa? Nasıl tecrit edersiniz? Ve bu sadece koddan ne yaptığını anlamak için yeni dev daha hızlı. Bu kadar mantığı tek bir satıra koymamanızı tavsiye ederim.
Dan

1
Güzel bir tek astar değil. X.join(Y.split(Z))sadece kıvrımlı bir yazma şeklidir Y.replace(X, Z)ve rangeçağrıyı list(...)ikisine de sarmanıza gerek yoktur .
Aran-Fey

1
@Dan evet, bunun için üzgünüm, (şimdi sadece bir satırda) :)
Reznik

1

re.subDinamik değiştirme için kullanma :

import re

text = "A %s B %s %s B %s"


def _fix_substitution_parms(raw_message):
    counter = 0
    def replace(_):
        nonlocal counter
        counter += 1
        return '{{{}}}'.format(counter - 1)
    return re.sub('%s', replace, raw_message)


print(_fix_substitution_parms(text))  # A {0} B {1} {2} B {3}

1
Bunun kaçan yer tutucuları ( %%s) hesaba katmadığını unutmayın - bu bir endişe kaynağıysa normal ifadeyi kullanabilirsiniz r'(?<!%)%s'.
Aran-Fey

Aptal soruya izin verirseniz: {{{}}}aslında ne hakkında?
GhostCat, Monica C.'yi selamlıyor

Kaçmaya biçimlendirme dize {biz yapmıyoruz \{zamanki bizim gibi {{.
Charif DZ

1

Jeneratör kullanma:

def split_and_insert(mystring):
    parts = iter(mystring.split('%s'))
    yield next(parts)
    for n, part in enumerate(parts):
        yield f'{{{n}}}'
        yield part

new_string = ''.join(split_and_insert("A %s B %s"))

-4

.Format ile denediniz mi?

string.format (0 = değer, 1 = değer)

Yani:

"A {0} B {1}".format(0=value, 1=value)


1
Bu yardımcısı olsun nasıl tahrik mi ediyor %siçine {}?
Aran-Fey
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.