Як перетворити% s на {0}, {1}… менш незграбним?


11

Я повинен взяти рядок, що містить заповнювачі, для подальшої заміни, наприклад:

"A %s B %s"

І перетворіть це на:

"A {0} B {1}"

Я придумав:

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

Це працює, але він відчуває себе супер незграбним і зовсім не "ідіоматичним" пітоном.

Як би виглядало добре, ідіоматичне рішення пітона?

Оновлення для уточнення:

  • отримані рядки не використовуються в python. Я робити потрібно число лічильників в там! (тому {}недостатньо добре)!
  • Мені потрібно дбати лише про %sрядки, оскільки повідомлення гарантовано використовувати лише %s(ні на що %i %f)

"re.sub" може взяти функцію заміни для динамічної заміни нумерованими дужками. До речі, заміна на {} без чисел також буде працювати.
Майкл Бутчер

3
Коли у вас є робоче рішення, і ви хочете його вдосконалити, будь ласка, розгляньте codereview.stackexchange.com
kojiro

@kojiro Це не працює для мене через "занадто незграбність" ;-)
GhostCat вітає Моніку С.

Відповіді:


5

Я хотів би зробити те , що Резник спочатку запропонував , а потім викликати .formatна те , що:

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

це буде працювати лише в тому випадку, якщо у вас є 2 %sу тексті?
Charif DZ

@CharifDZ та Aran-Fey - дивіться редагування. Ви просто порахувати їх , перш ніж руки ...
Ден

Виглядає як хороший компроміс ... читабельний, але не надто вигадливий.
GhostCat вітає Моніку C.

8

Використовуйте re.subза допомогою лямбда-функції для повторного використання підстановки один раз для кожного елемента та itertools.countотримання послідовних чисел:

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}'

Не забудьте зафіксувати це у функції, щоб виконати цю операцію не один раз, оскільки вам потрібно буде оновити itertools.count.


Приємно, хоча я вважаю його трохи "незрозумілим" ;-)
GhostCat вітає Моніку C.

@GhostCat це не затьмарено, лічильник - це генератор, коли коли-небудь, коли ти next(counter)його називаєш, дасть наступне значення, я завжди забуваю про цей генератор дуже приємна відповідь
Charif DZ

Регекс @GhostCat та функціональне програмування в одному рядку: -Я думаю, "неясність" залежить від того, наскільки ви звикли до цих інструментів.
jfaccioni

3

Я думаю, що це повинно працювати

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


1
@GhostCat не спокушаються однокласниками, пам’ятайте, що люди повинні підтримувати код
Dan

1
@Дан я знаю. Але я менше коду - це також менше код для підтримки.
GhostCat вітає Моніку С.

Це не менше, але це просто важче налагоджувати і важче майбутньому розробнику читати. Ця відповідь досить близька до ідентичної моїй, вона має ті ж виклики функцій (заміна заміни на розділення та приєднання), але що робити, якщо в проміжному кроці є проблема? Як би ви його ізолювали. І що швидше з нового нового розробника, щоб зрозуміти, що він робить тільки з коду. Я дуже рекомендую не вкладати стільки логіки в один рядок.
Ден

1
Не приємний однолінійний. X.join(Y.split(Z))це лише звичний спосіб написання Y.replace(X, Z), і немає необхідності завершувати rangeдзвінок list(...).
Аран-Фей

1
@Dan так, вибачте за це, (лише в одному рядку зараз) :)
Reznik

1

Використання re.subдля динамічної заміни:

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
Майте на увазі, що це не враховує уникнутих заповнювачів ( %%s) - якщо це викликає занепокоєння, ви можете скористатись регулярним виразом r'(?<!%)%s'.
Аран-Фей

Якщо ви дозволите дурне питання: про що {{{}}}насправді йдеться ?
GhostCat вітає Моніку C.

Формування рядків для втечі {ми не робимо \{як зазвичай {{.
Charif DZ

1

Використання генератора:

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?

string.format (0 = значення, 1 = значення)

Тому:

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


1
Як це допоможе хто - небудь перетворити %sв {}?
Аран-Фей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.