%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ではありません。

よくできた慣用的なpythonソリューションはどのように見えますか?

明確化のための更新:

  • 結果の文字列はPython内では使用されません。私はないそこにカウンター番号を必要とします!(それで{}十分ではありません)!
  • %sメッセージは使用するだけであることが保証されているため、文字列についてのみ気にする必要があります%s(まったく使用し%i %fない)

「re.sub」は、番号付きブレースで動的に置換するための置換として関数を使用できます。ちなみに、数字のない{}で置き換えることもできます。
Michael Butscher

3
あなたが働いて解決策を持っていて、それを改善したい場合は、codereview.stackexchange.comをご検討ください
小次郎

@kojiro「不格好すぎる」ため、私にとってはうまくいきません;-)
GhostCatはモニカCに敬意を表します。

回答:


5

Reznikが最初に提案したことを実行してから、それを要求.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

これは%sテキストに2 がある場合にのみ機能 しますか?
Charif DZ

@CharifDZとAran-Fey-編集を参照してください。あなたはそれらを手前に数えるだけです...
Dan

良い妥協のように見えます...読みやすいですが、派手ではありません。
GhostCatはモニカCに敬意を表します。

8

re.subラムダ関数と一緒に使用して、各要素に置換を1回再適用し、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正規表現と関数型プログラミングは同じ行にあります。-PI「曖昧さ」は、これらのツールにどれだけ慣れているかによって異なります。
jfaccioni

3

私はそれがうまくいくと思います

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


1
@GhostCatはワンライナーに誘惑されないでください。人々はコードを保守する必要があることを覚えておいてください
Dan

1
@ダンは知っています。しかし、コードが少ないほど、保守するコードも少なくなります。
GhostCatはモニカCに敬意を表します。

それは少なくはありませんが、デバッグするのが難しく、将来の開発者が読むのが難しくなります。この答えは私のものとかなり同じです、それは同じ関数呼び出し(スプリットとジョインの置換を交換)を持っていますが、中間のステップに問題がある場合はどうなりますか?どのように分離しますか。そして、コードからそれが何をするかを理解するために、ra new devの方が速いです。これだけのロジックを1行で記述しないことをお勧めします。
Dan

1
素敵なワンライナーではありません。X.join(Y.split(Z))は複雑な記述方法でY.replace(X, Z)あり、range呼び出しをラップする必要もありませんlist(...)
Aran-Fey

1
@Danはい、申し訳ありませんが、(現在は1行のみ):)
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'代わりに正規表現を使用できます。
Aran-Fey

あなたが愚かな質問を許可する場合:{{{}}}実際には何ですか?
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を助け{}ますか?
Aran-Fey
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.