Seite 1 von 2

String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 12:05
von rumpie
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

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 12:12
von jbs
Ich versteh den Vorteil von ``/`` gegenüber ``\`` bei deinem Problem nicht.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 12:27
von rumpie
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

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 12:36
von EyDu
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

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 12:37
von cofi
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?

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:00
von rumpie
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?

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:05
von Leonidas
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:14
von /me
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:20
von rumpie
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?

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:28
von cofi
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:47
von rumpie
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?

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 13:50
von /me
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 14:00
von sparrow
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 14:00
von /me
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

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 14:50
von rumpie
/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

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 15:01
von /me
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 15:34
von rumpie
/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...

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 15:48
von Leonidas
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.

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 12. Juni 2012, 15:53
von cofi
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 ...

Re: String: Ersetzen von Backslash als Slash

Verfasst: Dienstag 13. Oktober 2020, 08:33
von WE_Coder
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