Czy można wykonać częściowe formatowanie ciągu za pomocą zaawansowanych metod formatowania ciągów, podobnie jak w przypadku safe_substitute()
funkcji szablonu ciągu ?
Na przykład:
s = '{foo} {bar}'
s.format(foo='FOO') #Problem: raises KeyError 'bar'
python
string-formatting
P3trus
źródło
źródło
{bar:1.2f}
__missing__()
, zwróć wystąpienie klasy niestandardowej przesłaniającej__format__()
w taki sposób, aby zwrócić oryginalny symbol zastępczy, w tym specyfikację formatu. Dowód koncepcji: ideone.com/xykV7RJeśli wiesz, w jakiej kolejności formatujesz rzeczy:
Użyj tego w ten sposób:
Nie możesz określić,
foo
abar
jednocześnie - musisz to robić po kolei.źródło
s.format(foo='FOO',bar='BAR')
to nadal mam'FOO {bar}'
, bez względu na wszystko. Czy mógłbyś to wyjaśnić?Możesz skorzystać z
partial
funkcji, zfunctools
której jest krótka, najbardziej czytelna, a także opisuje intencje kodera:źródło
python from functool import partial s = "{foo} {bar}".format s_foo = partial(s, foo="FOO") print(s_foo(bar="BAR")) # FOO BAR print(s(foo="FOO", bar="BAR")) # FOO BAR
partial()
nie pomoże mi, jeśli potrzebuję przetworzyć częściowo sformatowany ciąg (to znaczy"FOO {bar}"
)."{foo} {{bar}}".format(foo="{bar}").format(bar="123")
z innych przykładów. Spodziewałbym się,"{bar} 123"
ale wychodzą"123 123"
.To ograniczenie
.format()
- niezdolność do częściowych podstawień - niepokoi mnie.Po
Formatter
przeanalizowaniu pisania niestandardowej klasy, jak opisano w wielu odpowiedziach tutaj, a nawet rozważeniu użycia pakietów innych firm, takich jak lazy_format , odkryłem znacznie prostsze wbudowane rozwiązanie: ciągi szablonówZapewnia podobną funkcjonalność, ale zapewnia również dokładną
safe_substitute()
metodę częściowego zastępowania . Ciągi szablonów muszą mieć$
prefiks (co wydaje się nieco dziwne - ale myślę, że ogólne rozwiązanie jest lepsze).Utworzono wygodne opakowanie na podstawie tego:
Podobnie opakowanie oparte na odpowiedzi Svena, które używa domyślnego formatowania ciągu:
źródło
Nie jestem pewien, czy jest to w porządku, jako szybkie obejście, ale co powiesz na to
? :)
źródło
Jeśli zdefiniujesz własną,
Formatter
która zastępujeget_value
metodę, możesz użyć jej do odwzorowania niezdefiniowanych nazw pól na dowolne:http://docs.python.org/library/string.html#string.Formatter.get_value
Na przykład, możesz zmapować
bar
do"{bar}"
ifbar
nie znajduje się w kwargs.Wymaga to jednak użycia
format()
metody obiektu Formatter, a nie metody ciąguformat()
.źródło
Wypróbuj to.
źródło
{{
i}}
jest sposobem na ucieczkę znaczniki formatujące, więcformat()
nie wykonuje podstawienie i zastępuje{{
i}}
z{
i}
, odpowiednio.{{ }}
działa tylko dla jednego formatu, jeśli chcesz zastosować więcej, musisz dodać więcej{}
. dawny.'fd:{uid}:{{topic_id}}'.format(uid=123).format(a=1)
zwróci błąd, ponieważ drugi format nie dostarczatopic_id
wartości.Dzięki komentarzowi Amber wymyśliłem to:
źródło
{field!s: >4}
Staje się{field}
Dla mnie to wystarczyło:
źródło
Wszystkie znalezione przeze mnie rozwiązania wydawały się mieć problemy z bardziej zaawansowanymi specyfikacjami lub opcjami konwersji. @ SvenMarnach's FormatPlaceholder jest cudownie sprytny, ale nie działa poprawnie z przymusem (np.
{a!s:>2s}
), Ponieważ wywołuje__str__
metodę (w tym przykładzie) zamiast__format__
i tracisz dodatkowe formatowanie.Oto, na czym skończyłem i niektóre z jego kluczowych funkcji:
str.format
(nie tylko mapowanie){k!s}
{!r}
{k:>{size}}
{k.foo}
{k[0]}
{k!s:>{size}}
Odkryłem problemy z różnymi implementacjami po napisaniu kilku testów dotyczących tego, jak chciałem, aby ta metoda zachowywała się. Są poniżej, jeśli ktoś uzna je za wnikliwe.
źródło
Moja sugestia byłaby następująca (przetestowana z Pythonem 3.6):
Aktualizacja: Jeszcze bardziej elegancki sposób (podklasy
dict
i przeciążanie__missing__(self, key)
) pokazano tutaj: https://stackoverflow.com/a/17215533/333403źródło
Zakładając, że nie użyjesz ciągu, dopóki nie zostanie całkowicie wypełniony, możesz zrobić coś takiego jak ta klasa:
Przykład:
źródło
Jest jeszcze jeden sposób, aby to osiągnąć, tj. Używając
format
i%
zastępując zmienne. Na przykład:źródło
Bardzo brzydkie, ale dla mnie najprostsze rozwiązanie to po prostu:
W ten sposób nadal możesz używać
tmpl
jako zwykłego szablonu i wykonywać częściowe formatowanie tylko wtedy, gdy jest to konieczne. Uważam, że ten problem jest zbyt trywialny, by użyć rozwiązania przesadnego, takiego jak Mohan Raja.źródło
Po przetestowaniu najbardziej obiecujących rozwiązań tu i ówdzie zdałem sobie sprawę, że żadne z nich tak naprawdę nie spełnia następujących wymagań:
str.format_map()
szablon;Napisałem więc własne rozwiązanie, które spełnia powyższe wymagania. ( EDYCJA : teraz wersja autorstwa @SvenMarnach - jak opisano w tej odpowiedzi - wydaje się obsługiwać narożne przypadki, których potrzebowałem).
Zasadniczo skończyło się na przeanalizowaniu ciągu szablonu, znalezieniu pasujących
{.*?}
grup zagnieżdżonych (za pomocąfind_all()
funkcji pomocniczej) i zbudowaniu sformatowanego ciągu stopniowo i bezpośrednio przy użyciu,str.format_map()
jednocześnie łapiąc jakikolwiek potencjałKeyError
.(Ten kod jest również dostępny w FlyingCircus - ZRZECZENIE SIĘ: Jestem jego głównym autorem.)
Zastosowanie tego kodu wyglądałoby tak:
Porównajmy to z moim ulubionym rozwiązaniem (autorstwa @SvenMarnach, który uprzejmie udostępnił tu i tam swój kod ):
Oto kilka testów:
i kod do uruchomienia:
w wyniku:
jak widać, zaktualizowana wersja wydaje się teraz dobrze radzić sobie z narożnymi przypadkami, w których wcześniejsza wersja zawodziła.
W międzyczasie są w ciągu ok. 50% siebie nawzajem, w zależności od faktycznego
text
formatu (i prawdopodobnie rzeczywistegosource
), alesafe_format_map()
wydaje się, że mają przewagę w większości przeprowadzonych przeze mnie testów (cokolwiek one oznaczają, oczywiście):źródło
{d[x]}
nie jest to prawidłowy ciąg formatu, o ile wiem.field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
jednocześniestr.format()
istr.format_map()
rozumie. Powiedziałbym, że jest wystarczająco dużo dowodów na to, że jest to prawidłowy ciąg formatu.str.format()
z indeksem niecałkowitym w nawiasach kwadratowych? Mogę sprawić, że działają tylko indeksy całkowite.a = dict(b='YAY!'); '{a[b]}'.format_map(dict(a=a))
dostajesz `` YAY! ''a[b]
w kodzie Pythona, ale w rzeczywistości jest toa["b"]
dzięki!Jeśli chcesz rozpakować słownik, aby przekazać argumenty
format
, jak w tym pokrewnym pytaniu , możesz użyć następującej metody.Najpierw załóżmy, że ciąg
s
jest taki sam jak w tym pytaniu:a wartości są podane w następującym słowniku:
Oczywiście to nie zadziała:
Możesz jednak najpierw pobrać
set
ze wszystkich nazwanych argumentóws
i utworzyć słownik, który mapuje argument na siebie zawinięty w nawiasy klamrowe:Teraz użyj
args
słownika, aby uzupełnić brakujące kluczereplacements
. W przypadku Pythona 3.5+ możesz to zrobić w jednym wyrażeniu :W przypadku starszych wersji Pythona możesz wywołać
update
:źródło
Podoba mi się odpowiedź @ sven-marnach. Moja odpowiedź to po prostu jego rozszerzona wersja. Umożliwia formatowanie bez słów kluczowych i ignoruje dodatkowe klucze. Oto przykłady użycia (nazwa funkcji jest odniesieniem do formatowania f-stringów w Pythonie 3.6):
A oto mój kod:
źródło
Jeśli często tworzysz szablony i stwierdzasz, że wbudowana w Pythonie funkcja tworzenia szablonów ciągów znaków jest niewystarczająca lub niezgrabna, spójrz na Jinja2 .
Z dokumentów:
źródło
Czytając komentarz @Sam Bourne, zmodyfikowałem kod @ SvenMarnach, aby działał poprawnie z przymusem (jak
{a!s:>2s}
) bez pisania niestandardowego parsera. Podstawowym pomysłem nie jest konwersja na łańcuchy, ale połączenie brakujących kluczy ze znacznikami przymusu.Użyj (na przykład) w ten sposób
Poniższe testy (inspirowane testami z @ norok2) sprawdzają dane wyjściowe dla tradycyjnego
format_map
isafe_format_map
opartego na powyższej klasie w dwóch przypadkach: z poprawnymi słowami kluczowymi lub bez nich.Jakie wyjścia
źródło
Możesz umieścić to w funkcji, która przyjmuje domyślne argumenty:
źródło