Seite 1 von 1

Strings "bearbeiten" mit Python

Verfasst: Sonntag 8. September 2002, 22:08
von man-draker
Hallo Leute,

nicht nur hier bin ich neu, auch was Python angeht. Daher stehe vor einem Problem, dass jeden Fortgeschrittenen wahrscheinlich den Kopf schütteln lässt:

Gegeben ist der Eintrag aus einem Mehrzeilen-Feld in einem HTML-Formular.
Dieser enthält unter anderem Zeilenschaltungen.
Das mag aber das Modul FlatDB, mit dessen Hilfe die Daten gespeichert werden sollen, garnicht. (Jedenfalls knallt es beim Wieder-Auslesen.)

Nun ist der Feldinhalt, wenn ich ihn aus cgi.userinput heraushole im Format string.
Also, als alter Pascal-Programmierer: String auf Zeichen kleiner SPACE gescannt und alle solchen durch Leerzeichen ersetzt

Nun ist aber der Typ string bei Python nicht veränderbar. :-(
Also schwupps in eine Liste konvertiert, diese bearbeitet und zurück in einen string konvertiert. Etwas umständlich und -- jetzt kommts -- das Ergebnis ist unbrauchbar. Aus "123" wird ['1','2','3'] und das ist nicht so ganz das, was ich mir vorstelle.

Ich suche also einen Weg
- entweder doch an Strings zu manipulieren oder
- aus einer Liste einen brauchbaren String zu machen.

Wer weiß Rat?

Re: Strings "bearbeiten" mit Python

Verfasst: Montag 9. September 2002, 09:38
von joerg
man-draker hat geschrieben: ...
Ich suche also einen Weg
- entweder doch an Strings zu manipulieren oder
- aus einer Liste einen brauchbaren String zu machen.

Wer weiß Rat?
Wie Du richtig erkannt hast, sind Strings in sich nicht veränderbar. Aber mußt Du wirklich genau diesen String verändern? Wenn nein, mache es doch so:

Code: Alles auswählen

>>> x = 'Hallo\nDu da!'
>>> print x
Hallo
Du da!
>>> x = x.replace('\n', ' ')
>>> print x
Hallo Du da!
x ist jetzt auch der geänderte String, der ursprüngliche wurde durch die Referenzzählung einfach weggeworfen - alles ok!

Und zum Problem Liste->String:

Code: Alles auswählen

>>> l = ['L', 'i', 's', 't', 'e']
>>> import string
>>> print string.join(l)
L i s t e
>>> print string.join(l, '')
Liste
>>> print string.join(l, '-')
L-i-s-t-e
join fügt zusammen, und setzt ein Trennzeichen ein. Da dieses auf das Leerzeichen voreingestellt ist, muß man explizit einen leeren String angeben, um kein Trennzeichen zu bekommen.

Verfasst: Montag 9. September 2002, 14:38
von RicmanX
Aus meinem Alpha-Status Gästebuch:
(meinst doch ne <textarea>!?)

Code: Alles auswählen

import re, cgi

puffer = cgi.FieldStorage()

kommentar = puffer["kommentar"].value
kommentar = re.sub("\r\n", "<br>", kommentar)
d.h.: substituiere (ersetze) alle "\r\n" (hab mir mal den Dictionary puffer voll anzeigen lassen und da sind das halt die Enter, nich nur die "\n") durch "<br>" und zwar beim Inhalt von kommentar.

Verfasst: Montag 9. September 2002, 15:07
von piddon
\r\n setzen, soweit ich weiss, nur Browser die auf Windows laufen. Wenn du Netscape o.ä. unter Linux benutzt, so hast du nur ein \r (oder war es nur \n? :) ) Also besser ist beides einzeln, bei Bedarf zu ersetzen.

Verfasst: Montag 9. September 2002, 17:09
von Gast
Zuerst einmal Dank an alle Hilfesteller.

1. Dass die Liste als String so seltsam aussah lag im Zweifel an meinem falschen Verstehen der Funktion str(), die halt keine liste -> string Funktion ist.

2. Die Antwort von joerg ist die exakt auf die gestellte Frage passende.

3. Die Antwort von RicmanX ist die, die das konkrete Problem am elegantesten (aus Sicht des Kodierenden) löst. Diese habe ich vorerst umgesetzt (und sie funktioniert).

4. Wenn die Benutzer es schaffen weitere unverdauliche Zeichen in die Eingabe zu packen, komme ich eventuell auf Methode Eins zurück, denn:

5. Weil zumindest der Konqueror (zu meiner Überraschung) einen Druck auf die Enter-Taste mit dem Einfügen von x0d x0a (oder \r\n) beantwortet, es andere Browseraber durchaus anders machen könnten (\n bei UNIX und ich fürchte \r beim Mac) suche ich jetzt zuerst einmal nach \r\n und anschließend sicherheitshalber noch einmal nach \n.
Hier das Ergebnis:

Code: Alles auswählen

def delEnter(such):
	s = re.sub("\r\n", "<br>", such)
	s = re.sub("\n", "<br>", s)
	return s
Ihr habt mir jedenfalls um die Klippe, an der ich hängen geblieben bin, herum geholfen. Dafür vielen Dank.

Verfasst: Montag 16. September 2002, 05:36
von RicmanX

Code: Alles auswählen

def delEnter(such): 
    return re.sub(os.linesep, "<br>", such)
:)

Verfasst: Montag 16. September 2002, 07:35
von Voges
Hallo!
RicmanX hat geschrieben:

Code: Alles auswählen

def delEnter(such): 
    return re.sub(os.linesep, "<br>", such)
Was bringt Dir das? Das Script unter Win ausgeführt ersetzt keine "\n" ohne "\r"' davor und unter Unix ausgeführt wird bei "\r\n" nur das "\n" ersetzt.

Jan

String-Methoden vs. Reguläre Ausdrücke

Verfasst: Montag 16. September 2002, 14:14
von joerg
Hallo Leute,

Ich persönlich finde re etwas übertrieben, um einzelne Zeichen oder klar definierte Zeichenketten zu suchen und zu ersetzen, da die String-Methoden das auch können, und zwar deutlich schneller. Bei mir liefert der folgende ganz einfache Test:

Code: Alles auswählen

import re, time
s = 'abcdefg' * 100
t = time.time()
for i in range(1000):
    s = re.sub('a', 'X', s)
    s = re.sub('X', 'a', s)
print time.time() - t
t = time.time()
for i in range(1000):
    s = s.replace('a', 'X')
    s = s.replace('X', 'a')
print time.time() - t
ungefähr einen Geschwindigkeitsvorteil vom Faktor 10 zugunsten der String-Methode! :D

Selbst wenn die Zeitmessung nicht so genau ist, und auf anderen Systemen vielleicht der Faktor nicht so hoch ist, sehe ich keinen Vorteil der re-Methoden, solange man reguläre Ausdrücke nicht wirklich braucht. Die Strings und ihre Methoden hat man immer, re muß man erst importieren.

Und bei der Ersetzungsmethode bin ich eher ein Fan der Trennung von Daten und Funktion, ich würde wahrscheinlich eine leicht erweiterbare Ersetzungstabelle und eine allgemeine Ersetzungsfunktion definieren, aber das ist wirklich Geschmackssache: :wink:

Code: Alles auswählen

transTab = (('\r', ''),('\n', '<br>'),('bla', 'fasel'))

def translate(s, tab=transTab):
    for old, new in tab:
        s = s.replace(old, new)
    return s

print translate('Dies \r\n ist \n ein Text')
Dies <br> ist <br> ein Text

Verfasst: Montag 16. September 2002, 16:45
von RicmanX
Voges hat geschrieben:Hallo!
RicmanX hat geschrieben:

Code: Alles auswählen

def delEnter(such): 
    return re.sub(os.linesep, "<br>", such)
Was bringt Dir das? Das Script unter Win ausgeführt ersetzt keine "\n" ohne "\r"' davor und unter Unix ausgeführt wird bei "\r\n" nur das "\n" ersetzt.

Jan
Unix hat nur "\n", Windows hat "\r\n" usw.
Und das os Modul fragt nach dem OS und setzt entsprechend den Richtigen LineSeparator.
Da eine <textarea> immer nur diese OS spezifischen Zeilenumbrüche verwendet und es hier um HTML geht, ist es ja das Ziel mit möglich wenigst Abfragen/Aktionen diesen Zeilenumbruch zu ersetzen. Und genau das macht diese Funktion: je nach OS (bzw. mit Browser) wird der Zeilenumbruch zu nem HTML Zeilenumbruch gewandelt. Wozu unbedingt etwas universelles, aber langsameres machen, womit das Script eh nie konfrontiert wird?

Verfasst: Montag 16. September 2002, 18:09
von Voges
Hallo!
RicmanX hat geschrieben: Unix hat nur "\n", Windows hat "\r\n" usw.
Und das os Modul fragt nach dem OS und setzt entsprechend den Richtigen LineSeparator.
Ich verstehe es immer noch nicht. Es geht doch um ein CGI-Script, also ein Script, das auf dem Server läuft. Was hilft es Dir zu wissen, wie der Lineseperator des Server-OS lautet (bei Linux z.B. "\n"), wenn Dir der Client (sprich Browser) was anderes im Textarea-Text für Umbrüche vorsieht (bei Netscape/Win z.B. "\r\n"). Ein re.sub(os.linesep, "<br>", such) macht dann aus "bla\r\nblub" ein "bla\r<br>blub" (hab' ich getestet). Vielleicht reden wir aber auch von verschiedenen Sachen ;-)

Jan

Verfasst: Sonntag 22. September 2002, 14:56
von hans
Voges hat geschrieben: Und das os Modul fragt nach dem OS und setzt entsprechend den Richtigen LineSeparator.
Mal ne bescheidene Zwischenfrage, was passiert, wenn die Datei auf einen Server hochgeladen wird und das Script auf dem Server ausgeführt wird? Dann gibt es vier Möglichkeiten: WW, WU, UW, UU (1.Stelle OS Server, 2. Stelle OS Client). Dieses Script dürfte doch nur bei Kombination WW oder UU greifen.

Gibts Alternativen? Unter Linux / Unix steht ja mit file ein entsprechendes Programm zur Verfügung. Bei Windows ist mir derartiges nicht bekannt.

Andererseits, ist es wichtig, dass ich hier nach OS unterscheide? Enternen wir doch erst mal Ballast (/r) und ersetzen dann /n. Sollte doch Sauber sein oder?

Hans

Verfasst: Sonntag 22. September 2002, 18:26
von RicmanX
Ich weiß nicht ob entfernen so gut ist, schließlich kann es eine beliebige Eingabe sein. Da ist ersetzen irgendwie schon besser.

Verfasst: Sonntag 22. September 2002, 21:19
von hans
Also ein /r ohne /n kenne ich nur von Druckdateien, nämlich bei Nadelprintern. hallo Welt/rhallo Welt sorgt dafür, dass der Wagen einmal nich links gefahren wird ohne dabei einen Zeilenvorschub zu machen und die Zeile dann nochmal zu Drucken. Das ganze erscheint dann FETT

Ich denke mal, das es in diesem Fall nicht um eine Druckdatei handelt. Und wenn die Datei nicht verändert werden darf, dann arbeite doch mit einer Kopie.

Wie war das eigentlich mit Macs, BeOS und co? /n oder /r/n ?

Hans

Verfasst: Freitag 11. Oktober 2002, 19:20
von Dookie
Hi hans,

Win = /r/n
Unix = /n
Mac = /r