String: Ersetzen von Backslash als Slash

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

Hallo,

ich komme einfach nicht weiter mit meinem Problem. Und auch die Suche half nicht (oder ich hatte nicht die richtigen "Fragen" in der Suche. Deswegen hier meine Frage(n) an euch:

Problem: Ich habe einen String, dieser ist kein Rohstring und beinhaltet Datei inkl. Verzeichnis wie z.B. das hier:

Code: Alles auswählen

sString = "c:\Program Files\7-Zip\7zFM.exe"
Hier möchte ich nun einfach die Datei starten mit

Code: Alles auswählen

  
# das funktioniert nicht          
subprocess.Popen(sString)

# aber das funktioniert
#subprocess.Popen(r"c:\Program Files\7-Zip\7zFM.exe")  
#subprocess.Popen("c:\Windows\calc.exe")  
2 Probleme habe ich erkannt:

- wenn im Ordnernamen ein Leerzeichen ist
- Mit einem Rohstring klappt der Aufruf

-> Als Lösung möchte ich die Backslash in Slash konvertieren. Doch damit scheitere ich bis jetzt.
re.sub oder string.replace erkennen als Pattern meinen Backslash nicht an :-(

Wie kann ich diese Konvertierung hinbekommen oder einen Aufruf der Datei ohne Fehlermeldung?

Viele Dank für eure Hilfe und viele Grüße
rumpie
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Ich versteh den Vorteil von ``/`` gegenüber ``\`` bei deinem Problem nicht.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

jbs hat geschrieben:Ich versteh den Vorteil von ``/`` gegenüber ``\`` bei deinem Problem nicht.

Code: Alles auswählen

# das funktioniert auch (habe ich vergessen zu posten)
subprocess.Popen("c:/Program Files/7-Zip/7zFM.exe")
deswegen wäre ein Austausch eine mögliche Lösung für mich.

Viele Grüße
rumpie
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo,

du hast dein Problem lediglich nicht verstanden. Wenn du

Code: Alles auswählen

spam = "\7"
schreibst, dann ist dort kein Backslash im Text gespeichert. Dieser leitet eine Escapesequenz ein, welche dazu gedacht sind, nicht darstellbare Zeichen (oder Zeichen die sonst mit der Syntax kollidieren würden) in Strings zu speichern. Das siehst du auch, wenn du dir die Größe des Strings anschaust:

Code: Alles auswählen

>>> len("\7")
1
und im Gegensatz zu Rawstrings:

Code: Alles auswählen

>>> len(r"\7")
2
Das r vor dem String bewirkt hier also nichts anderes, als dass der Backslash intern als Backslash gespeichert wird. Was das gleiche ist wie:

Code: Alles auswählen

>>> "\\7"
'\\7'
>>> len("\\7")
2
\\ ist die Escapesquenz für einen Backslash. Du erzeugst also einen Backslash gefolgt von einer 7. Wie du siehst, hast du gar keine (sinnvolle) Möglichkeit um deine Idee umzusetzen. Wenn du Pfade in deinen Code schreibst, dann benutze einfach Raw-Strings. Damit machst du nichts falsch.

Sebastian
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

rumpie hat geschrieben:

Code: Alles auswählen

# das funktioniert auch (habe ich vergessen zu posten)
subprocess.Popen("c:/Program Files/7-Zip/7zFM.exe")
deswegen wäre ein Austausch eine mögliche Lösung für mich.
Der subprocess Aufruf ist falsch, richtig waere

Code: Alles auswählen

subprocess.Popen(["C:/Pro....exe"]
Backslashes sind nur in String-Literalen ein "Problem", da sie dort als Escape-Zeichen fungieren. Wenn du also ein String-Literal falsch benutzt hast, kannst du es nachtraeglich nicht beheben, da es ueberhaupt keinen Backslash mehr hat.

Darum ist der Austausch auch keine Loesung. In wieweit Spaces ein Problem sein sollen, kann ich nicht nachvollziehen, kann es vielleicht sein, dass du subprocess mit `shell=True` oder `os.system` benutzt?
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

Hallo Sebastian,

ich habe schon das Problem verstanden - eben dass es eine Escapesequenz einleitet.

Nur bekomme ich meinen Wert aus der Registry gelesen (oberer Aufruf ist nur als Beispiel gedacht, da gleicher Effekt) und erhalte da einen String mit Backslashes. Ich habe versucht diese als "normale Zeichen" wieder zu werten - leider ohne Erfolg. Oder kann ich mit _winreg auch rawstrings auslesen?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

String und Raw-Strings sind das gleiche. In Raw-Strings werden Escape-Sequenzen nicht ausgewertet (oder auch automatisch escaped, da gabs sogar einen tollen deutschen Term, gefluchtet), aber was rauskommt ist ein völlig normaler String. Im Lisp-Jargon würde man wohl sagen dass Raw-Strings nur Reader-Makros sind.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

rumpie hat geschrieben:Oder kann ich mit _winreg auch rawstrings auslesen?
Rawstrings dienen nur der Codierung im Quelltext und sind im Speicher ganz normale Strings. Wenn du die Daten von irgendwoher einliest sollten sie folglich korrekt sein.
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

Leonidas hat geschrieben:String und Raw-Strings sind das gleiche. In Raw-Strings werden Escape-Sequenzen nicht ausgewertet (oder auch automatisch escaped, da gabs sogar einen tollen deutschen Term, gefluchtet), aber was rauskommt ist ein völlig normaler String. Im Lisp-Jargon würde man wohl sagen dass Raw-Strings nur Reader-Makros sind.
gefluchtet - schönes Wort ;-)

Was mich verwundert ist, wenn ich schreibe

Code: Alles auswählen

x = r"123"
habe ich einen Rawstring

Aber bei einer Übergabe eines schon bestehenden Strings (ohne das r") kann ich nichts mehr ändern bzgl. der internen Backslash.

Hmm - wie kann ich mein Problem lösen?
Ich hole mir einen Schlüsselinhalt aus der Registry, welcher als Inhalt einen Pfad hat. Doch bei diesen wird dann der "\" als Escapesequenzeinleitung gewertet und kann nicht mehr zu einem "normalen" Zeichen "mutieren". Gibt es da eine Möglichkeit vielleicht schon beim Abholen des Schlüsselinhalts?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

rumpie hat geschrieben:Doch bei diesen wird dann der "\" als Escapesequenzeinleitung gewertet und kann nicht mehr zu einem "normalen" Zeichen "mutieren".
Genau das passiert nicht und das wollten dir schon die letzten 5 Posts erklaeren. Raw-Strings sind fuer String-Literale da, also solche die "hartkodiert" im Quelltext vorkommen. Alle anderen Strings haben die Backslash Besonderheit nicht.
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

cofi hat geschrieben:
rumpie hat geschrieben:Doch bei diesen wird dann der "\" als Escapesequenzeinleitung gewertet und kann nicht mehr zu einem "normalen" Zeichen "mutieren".
Genau das passiert nicht und das wollten dir schon die letzten 5 Posts erklaeren. Raw-Strings sind fuer String-Literale da, also solche die "hartkodiert" im Quelltext vorkommen. Alle anderen Strings haben die Backslash Besonderheit nicht.
Ok, danke. Irgendwie habe ich es doch noch nicht so verstanden, warum ich mein Problem habe:

Windows - Python 2.7. Ich habe hier mal den Code zusammenkopiert:

Code: Alles auswählen

#!/usr/bin/python

import _winreg, ConfigParser, subprocess

if __name__ == '__main__':

    # Installpfad aus Registry
    key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, sString)
    sInstallPath, type1 = _winreg.QueryValueEx(key, "Install Path")
    # sInstallPath = "c:\Program Files"

    # Rel. Position der exe-Datei aus der ini-Datei
    IniData = ConfigParser.ConfigParser()
    IniData.read("settings.ini")
    sRelExe = IniData.get("SETTINGS", "Loc_exe")
    # ini-Inhalt: Loc_exe = \bla\blubb.exe


    # String zusammensetzen + Programm starten
    sExe= sInstallPath + sRelExe
    subprocess.Popen(sExe)
Da passieren eben die oben im Eingangspost genannten Effekte. Was mache ich da mit meinem String falsch?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

rumpie hat geschrieben:Was mich verwundert ist, wenn ich schreibe

Code: Alles auswählen

x = r"123"
habe ich einen Rawstring
Das Ergebnis ist in beiden Fällen ein normaler String.

Code: Alles auswählen

>>> type('123')
<type 'str'>
>>> type(r'123')
<type 'str'>
Es gibt keine Rawstring-Objekte in Python. Die Angabe des führenden r dient im Sourcecode - und zwar ausschließlich im Sourcecode - dazu, dass der Backslash wie ein normales Zeichen statt als Einleitung einer Escape-Sequenz gesehen wird. Wenn du also Daten aus einer Datei oder woandersher einliest hast du einen ganz normalen String in dem auch beim Vorhandensein eines Backslash beim Einlesen nichts ersetzt wird.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

rumpie hat geschrieben:Da passieren eben die oben im Eingangspost genannten Effekte. Was mache ich da mit meinem String falsch?
Welche Effekte genau? Was sagt die Fehlermeldung? Was genau ist der Inhalt der Zeichenkette wenn du sie öffnen willst?

Pfade solltest du mit os.path.join() zusammen bauen.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

rumpie hat geschrieben:Was mache ich da mit meinem String falsch?
Du gibst den ersten Parameter von Popen falsch an. Erwartet wird eine Argumentliste.

Code: Alles auswählen

subprocess.Popen([sExe])

Zwei Tipps noch.

Bitte gewöhne dir diese s-Präfixe für Strings ab. Erstens macht das heute kein normaler Mensch mehr, zweitens kann das gerade bei dynamischen Sprachen plötzlich völlig falsch sein und drittens hat Charles Simonyi bei der Erfindung der Ungarischen Notation niemals beabsichtigt, dass man den Datentyp dort verwendet.


Pfade sollte man mit os.path.join statt mit normaler Stringverkettung zusammensetzen.

Code: Alles auswählen

>>> print os.path.join(r"c:\Program Files", r"bla\blubb.exe")
c:\Program Files\bla\blubb.exe
Vorsicht ist allerdings bei führenden Pfadtrennern geboten:

Code: Alles auswählen

>>> print os.path.join(r"c:\Program Files", r"\bla\blubb.exe")
\bla\blubb.exe
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

/me hat geschrieben: Zwei Tipps noch.

Bitte gewöhne dir diese s-Präfixe für Strings ab. Erstens macht das heute kein normaler Mensch mehr, zweitens kann das gerade bei dynamischen Sprachen plötzlich völlig falsch sein und drittens hat Charles Simonyi bei der Erfindung der Ungarischen Notation niemals beabsichtigt, dass man den Datentyp dort verwendet.


Pfade sollte man mit os.path.join statt mit normaler Stringverkettung zusammensetzen.

Code: Alles auswählen

>>> print os.path.join(r"c:\Program Files", r"bla\blubb.exe")
c:\Program Files\bla\blubb.exe
Vorsicht ist allerdings bei führenden Pfadtrennern geboten:

Code: Alles auswählen

>>> print os.path.join(r"c:\Program Files", r"\bla\blubb.exe")
\bla\blubb.exe
Danke für die Tipps. Ich habe es mal getestet, aber

Code: Alles auswählen

#!/usr/bin/python

import _winreg, ConfigParser, subprocess, os

if __name__ == '__main__':

    InstallPath = "c:\Program Files"
    RelExe = "7-Zip\7zFM.exe"
    Exe1 = os.path.join(InstallPath, RelExe)
    print Exe1
    subprocess.Popen([Exe1])
Output:

Code: Alles auswählen

c:\Program Files\7-ZipzFM.exe
Traceback (most recent call last):
  File "D:\Projekte\Workspace\Test_general\src\problem.py", line 11, in <module>
    subprocess.Popen([Exe1])
  File "C:\Python27\lib\subprocess.py", line 672, in __init__
    errread, errwrite)
  File "C:\Python27\lib\subprocess.py", line 882, in _execute_child
    startupinfo)
WindowsError: [Error 2] Das System kann die angegebene Datei nicht finden
-> der Pfad ist falsch, da bei RelExe der Backslash eine Escapesequenz ist..

Dann folgende Änderung

Code: Alles auswählen

RelExe = "7-Zip/7zFM.exe"
(also in meinen ini-Eintrag anstatt den Backslash einen Slash)
und siehe da - es funktioniert.
Ich komme also weiter, vielen Dank für eure Hilfe und Anregungen.

Viele Grüße
rumpie
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

rumpie hat geschrieben:

Code: Alles auswählen

#!/usr/bin/python

import _winreg, ConfigParser, subprocess, os

if __name__ == '__main__':
    InstallPath = "c:\Program Files"
    RelExe = "7-Zip\7zFM.exe"
    Exe1 = os.path.join(InstallPath, RelExe)
    print Exe1
    subprocess.Popen([Exe1])
Arghhhhh!

Hier liest du die Strings ja auch nicht aus einer Datei oder meinetwegen aus der Registry sondern definierst sie im Sourcecode. Hier müsstest du die Strings natürlich entweder als "7-Zip\\7zFM.exe" oder r"7-Zip\7zFM.exe" definieren um im daraus resultierenden String genau einen Backslash zu haben.

Schau dir bitte an wie die Repräsentation der Strings aussieht:

Code: Alles auswählen

>>> r"7-Zip\7zFM.exe"
'7-Zip\\7zFM.exe'
>>> "7-Zip\7zFM.exe"
'7-Zip\x07zFM.exe'
Im zweiten String steht jetzt nicht die Zeichensequenz "\ x 0 7". Das ist nur die Darstellung des einen Zeichens das dort steht und das keine druckbare Entsprechung hat, nämlich das Zeichen mit dem ASCII-Code 7.
rumpie
User
Beiträge: 11
Registriert: Montag 17. August 2009, 14:25

/me hat geschrieben:
rumpie hat geschrieben:

Code: Alles auswählen

#!/usr/bin/python

import _winreg, ConfigParser, subprocess, os

if __name__ == '__main__':
    InstallPath = "c:\Program Files"
    RelExe = "7-Zip\7zFM.exe"
    Exe1 = os.path.join(InstallPath, RelExe)
    print Exe1
    subprocess.Popen([Exe1])
Arghhhhh!

Hier liest du die Strings ja auch nicht aus einer Datei oder meinetwegen aus der Registry sondern definierst sie im Sourcecode. Hier müsstest du die Strings natürlich entweder als "7-Zip\\7zFM.exe" oder r"7-Zip\7zFM.exe" definieren um im daraus resultierenden String genau einen Backslash zu haben.

Schau dir bitte an wie die Repräsentation der Strings aussieht:

Code: Alles auswählen

>>> r"7-Zip\7zFM.exe"
'7-Zip\\7zFM.exe'
>>> "7-Zip\7zFM.exe"
'7-Zip\x07zFM.exe'
Im zweiten String steht jetzt nicht die Zeichensequenz "\ x 0 7". Das ist nur die Darstellung des einen Zeichens das dort steht und das keine druckbare Entsprechung hat, nämlich das Zeichen mit dem ASCII-Code 7.
Ja, ist hier nur als (schlechtes) Beispiel drin. Ich lese beide Strings aus der Registry bzw. einer ini-Datei - siehe obere Antwort.
Ich wollte damit nur anzeigen, wie ich es lösen konnte, nämlich meinen Eintrag (den in der ini-Datei) konnte ich anpassen, der in der Registry mit den Backslash als Pfadtrenner drin muss ich nehmen wie er ist.
Das Problem (was du auch noch mal aufzeigtest) habe ich verstanden gehabt...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

rumpie hat geschrieben:Ja, ist hier nur als (schlechtes) Beispiel drin. Ich lese beide Strings aus der Registry bzw. einer ini-Datei - siehe obere Antwort.
In dem Fall sollte das "Problem" niemals auftauchen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

rumpie hat geschrieben:Ja, ist hier nur als (schlechtes) Beispiel drin. Ich lese beide Strings aus der Registry bzw. einer ini-Datei - siehe obere Antwort.
Das einzige brauchbare Beispiel an der Stelle ist genau das zu tun. Schreibe die Strings in eine Datei, lies sie wieder aus und versuch deinen Code _damit_.
rumpie hat geschrieben:Das Problem (was du auch noch mal aufzeigtest) habe ich verstanden gehabt...
Dem wuerde ich nicht zustimmen ...
WE_Coder
User
Beiträge: 1
Registriert: Dienstag 13. Oktober 2020, 08:20

Ich hatte dieses Problem mit filedialog.askdirctory() und dem Backslash auch. Die Lösung ist aber eigentlich ganz einfach:

Code: Alles auswählen

>>> from tkinter import filedialog
>>> system_pfad = filedialog.askdirectory(title = "Ordner wählen")
>>> print(system_pfad)
C:/Windows/System
>>> pfad_neu = system_pfad.replace("/", "\\")
>>> print(pfad_neu)
C:\Windows\System
>>>
Über Sinn und Unsinn dieser Methode will ich gar nicht diskutoeren. Bei mit hat das so wunderbar funktioniert :D
Antworten