Seite 1 von 1
Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 14:44
von warumweshalbwieso
Hallo zusammen,
ich habe gerade die f-strings für mich entdeckt und spiele nun etwas damit rum:
Code: Alles auswählen
def heading(text, level=1):
levels = {1: "#", 2: "*", 3: "=", 4: "-", 5: "^", 6: '"'}
return f"{text}\n{len(text) * levels[level]}"
def bullet_list(items, enumerated=False, starting_number=1):
bullet_list = ""
if enumerated is False:
for item in items:
bullet_item = f"- {item}\n"
bullet_list += bullet_item
return bullet_list
elif enumerated is True:
for (n, item) in enumerate(items):
bullet_item = f"{n + starting_number}. {item}\n"
bullet_list += bullet_item
return bullet_list
if __name__ == '__main__':
import random
import textwrap
n_of_entries = random.randint(3, 8)
entries = [random.randint(10000, 90000) for entry in range(n_of_entries)]
rst_text = textwrap.dedent(
f"""{heading("Example of Randomly Generated Bullet Lists")}
{heading("Normal Bullet List", level=2)}
This is a normal bullet list:
{bullet_list(entries)}
{heading("Enumerated Bullet List", level=2)}
And this is a enumerated bullet list:
{bullet_list(entries, enumerated=True)}"""
)
print(rst_text)
Das funktioniert auch wunderbar, nur die Einrückung passt mir nicht. Die Ausgabe sieht zum Beispiel so aus:
Code: Alles auswählen
Example of Randomly Generated Bullet Lists
##########################################
Normal Bullet List
******************
This is a normal bullet list:
- 50289
- 76920
- 25057
- 70780
- 32732
Enuemrated Bullet List
**********************
And this is a enumerated bullet list:
1. 50289
2. 76920
3. 25057
4. 70780
5. 32732
Google hat mich zu textwrap.dedent() geführt, aber anscheinend verstehe ich nicht, wie das funktioniert, es macht nämlich keinen unterschied, ob ich die Funktion verwende oder nicht. Kann mir hier vielleicht jemand auf die Sprünge helfen?
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 15:08
von DeaD_EyE
Das liegt an der fehlenden Einrückung in der ersten Zeile. Da dort keine Leerzeichen vorhanden sind, rückt er den Rest auch nicht ein.
Damit die Einrückung in der ersten Zeile gleich der restlichen ist, einfach nach den Triple-Quotes eine neue Zeile anfangen und in dem Block bleiben.
Code: Alles auswählen
if __name__ == '__main__':
...
rst_text = textwrap.dedent(
f"""
{heading("Example of Randomly Generated Bullet Lists")}
{heading("Normal Bullet List", level=2)}
This is a normal bullet list:
{bullet_list(entries)}
{heading("Enumerated Bullet List", level=2)}
And this is a enumerated bullet list:
{bullet_list(entries, enumerated=True)}
"""
)
print(rst_text)
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 15:33
von warumweshalbwieso
Hab's jetzt mal genauso gemacht und dann kommt das hier raus:
Code: Alles auswählen
Example of Randomly Generated Bullet Lists
##########################################
Normal Bullet List
******************
This is a normal bullet list:
- 43371
- 52346
- 34967
- 86435
- 61904
- 16934
Enumerated Bullet List
**********************
And this is a enumerated bullet list:
1. 43371
2. 52346
3. 34967
4. 86435
5. 61904
6. 16934
Bekomme eine Leerzeile am Anfang, die ich aber durch einen Backslash wieder entfernt kriege. Aber die Einrückung ist fast unverändert, außer, dass die erste Überschrift nun auch eingerückt ist...
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 16:01
von __blackjack__
@warumweshalbwieso: Natürlich macht `detent()` keinen Unterschied. Was hast Du denn da erwartet und warum? Das entfernt Leerzeichen am Anfang von Zeilen und zwar die kleinste gemeinsame Anzahl. Wenn in den Ausgangsdaten Zeilen vorkommen die direkt am Zeilenanfang beginnen, ohne führende Leerzeichen, dann sind das logischerweise 0 Leerzeichen die entfernt werden = keine Änderung.
Sonstige Anmerkungen zum Quelltext: `levels` in `heading()` könnte eine Liste sein und ich würde dann auch einfach bei 0 mit dem Zählen anfangen wie das bei Programmen üblich ist (ausser bei Sprachen bei denen der Index in Sequenztypen mit 1 statt mit 0 anfängt).
Wobei man wenn das reStructuredText werden soll für das Level 0 auch den Dokumentitel formatieren könnte mit einer Zeile über und unter dem Text.
`bullet_list()` sind eigentlich zwei Funktionen. Oder man sollte das so umschreiben das die Unterscheidung nicht darin besteht das entweder die eine Hälfte vom Code in der Funktion ausgeführt wird oder die andere.
Das mit dem ``+=`` ist auch „unpythonisch“ weil wenn der Intepreter nicht trickst sehr ineffizient. Zeichenketten sind unveränderlich, also muss man damit rechnen das bei jedem ``+``/``+=`` Speicher für den Inhalt beider Zeichenketten reserviert wird, und beie Zeichenketten dort hinein kopiert werden. Da werden dann immer mehr Daten sinnlos in der Gegend herum kopiert. Idiomatisch ist es die Daten in einer Liste zu sammeln oder einen Iterator zu erstellen und dann mit ``"".join(…)`` das Ergebnis zu erstellen.
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 16:12
von __blackjack__
@warumweshalbwieso: Huh, Du hast in der Funktion `bullet_list()` einen lokalen Namen `bullet_list`. Das ist ein bisschen verwirrend.
`bullet_list()` triffts IMHO auch nicht so ganz. Erstens ist es keine Tätigkeit und zweitens ist eine nummerierte Liste keine „bullet list“ weil da ja Nummern statt „bullet points“ sind.
Code: Alles auswählen
from itertools import count, repeat
def format_list(items, enumerated=False, starting_number=1):
prefixes = (
(f"{i}." for i in count(starting_number))
if enumerated
else repeat("-")
)
return "".join(
f"{prefix} {item}\n" for prefix, item in zip(prefixes, items)
)
Wenn man jetzt noch das „bullet point“-Zeichen als Argument übergeben möchte, dann gilt aber wieder dass das eigentlich zwei verschiedene Funktionen sind.
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 16:38
von warumweshalbwieso
Danke für die Erklärung, jetzt hab ich dedent verstanden. Aber wie bekomme ich dann die Einrückungen korrigiert? Meine geringste Anzahl an Leerzeichen ist ja bereits null, deshalb wird auch nichts zurückgesetzt.
Und danke auch für deine angepasste Funktion und die Kommentare zu meinen. Ich habe sie mal überarbeitet:
Code: Alles auswählen
def format_heading(text, level=0):
levels = ["#", "*", "=", "-", "^", '"']
heading = f"{text}\n"
lining = f"{len(text) * levels[level]}\n"
if level == 0:
return f"{lining}{heading}{lining}"
else:
return f"{heading}{lining}"
def format_bullet_list(items, bullet_point="-"):
bullet_list = []
for item in items:
bullet_item = f"{bullet_point} {item}\n"
bullet_list.append(bullet_item)
return "".join(bullet_list)
def format_enumerated_list(items, starting_number=1):
enumerated_list = []
for (n, item) in enumerate(items):
enumerated_item = f"{n + starting_number}. {item}\n"
enumerated_list.append(enumerated_item)
return "".join(enumerated_list)
So besser?
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 18:52
von __blackjack__
@warumweshalbwieso: Ich denke das ist einfach kein guter Fall für f-Zeichenkettenliterale in einer Form wo man am Ende noch so etwas wie die Einrückung geradeziehen muss, sondern eher ein Fall für Templates, entweder für die `format()`-Methode oder für `string.Template` oder eine Template-Engine wie beispielsweise `jinja2`. Da kann man die Vorlage mit Platzhaltern auf Modulebene als Konstante definieren, ohne unnötige Einrückung. Oder extern als Datei wenn es umfangreicher wird und/oder man vielleicht auch Syntaxhervorhebung im Editor haben möchte.
Oder man gestaltet die API anders, so dass man nicht eine grosse Zeichenkette hat mit Platzhaltern sondern Funktionen/Klassen schreibt die eher wie Textauszeichnung wirken. So in Richtung:
Code: Alles auswählen
rst_text = Document(
[
Heading("Example of Randomly Generated Bullet Lists"),
Heading("Normal Bullet List", level=2),
Paragraph(["This is a normal bullet list:", BulletList(entries)]),
Heading("Enumerated Bullet List", level=2),
Paragraph(
[
"And this is an enumerated bullet list:",
EnumeratedList(entries),
]
),
]
)
print(rst_text)
Re: Einrückung mulit-line string entfernen
Verfasst: Mittwoch 4. März 2020, 19:49
von LeSchakal
Die Einrückungen kriegst du am einfachsten weg, wenn du keine Einrückungen im f-String verwendest. Schaut zwar nicht schön aus, aber...
Code: Alles auswählen
if __name__ == '__main__':
import random
import textwrap
n_of_entries = random.randint(3, 8)
entries = [random.randint(10000, 90000) for entry in range(n_of_entries)]
rst_text = textwrap.dedent(
f"""
{heading("Example of Randomly Generated Bullet Lists")}
{heading("Normal Bullet List", level=2)}
This is a normal bullet list:
{bullet_list(entries)}
{heading("Enumerated Bullet List", level=2)}
And this is a enumerated bullet list:
{bullet_list(entries, enumerated=True)}
"""
)
print(rst_text)