Smarte Methode zum Dateipfad kürzen gesucht

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Kurzer »

Moin zusammen,

gibt es in PB eine clevere Methode (unter Windows), um von einer Verzeichnisebene (als String) die n-te übergeordnete Verzeichnisebene anzusprechen?

Angenommen ich habe das Verzeichnis D:\Obst\Äpfel\Reife\Greenstar\ ermittelt und möchte auf D:\Obst\Äpfel\Reife\ mittels Delete() oder Rename() zugreifen.

Muss ich den String dann zwingend vorher kürzen (StringField, CountString) oder gibt es sowas wie "\.." für ein Verzeichnis höher? Meine Tests in diese Richtung haben bisher leider nicht funktioniert.

Kurzer
Zuletzt geändert von Kurzer am 08.03.2020 19:33, insgesamt 1-mal geändert.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
mk-soft
Beiträge: 3700
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von mk-soft »

Ohne Worte :wink:

Code: Alles auswählen

;-TOP by mk-soft ;)

Procedure.s GetParentPath(Path.s, n = 1)
  For i = 1 To n
    If Right(Path, 1) = #PS$
      Path = Left(Path, Len(Path) - 1)
    EndIf
    Path = GetPathPart(Path)
  Next
  ProcedureReturn Path
EndProcedure

Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\")
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 2)
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 3)
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 4)

Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Kurzer »

Das ist smart! :allright:

Wenn ich mir da mein Konstrukt ansehe... :lol:

Code: Alles auswählen

EnableExplicit

Procedure.s PathPart (sPath.s, iLevelsUp.i)
	#Separator = "\"
	Protected.i i, iOutPathLen, iPathLen = Len(sPath), iCountLevels
	Protected.s sTemp = ReplaceString(sPath, "/", #Separator)
	
	; Pfad und übergeordnete Verzeichnisebene prüfen
	If iPathLen = 0 Or iLevelsUp < 1 : ProcedureReturn sPath : EndIf
	
	If Right(sTemp, 1) = #Separator
		sTemp = Left(sTemp, iPathLen - 1)
	EndIf
	
	iCountLevels = CountString(sTemp, #Separator) + 1
	
	; Anzahl der Unterverzeichnisse im Pfad prüfen
	If iCountLevels = 1
		ProcedureReturn sPath
	ElseIf iLevelsUp > iCountLevels
		ProcedureReturn ""
	EndIf
	
	For i = 1 To iCountLevels - iLevelsUp
		iOutPathLen + Len(StringField(sTemp, i, #Separator)) + 1 ; + 1 für den Separator
	Next i
	
	ProcedureReturn Left(sPath, iOutPathLen)
EndProcedure

Debug PathPart("D:\Computer\Level1/Level2\Level3\", 0)
Debug PathPart("D:/Computer\Level1\Level2/Level3", 1)
Debug PathPart("D:/Computer/Level1/Level2/Level3", 2)
Wobei ich aber auch gemischte Path-Separatoren unterstützen wollte.

Vielen Dank für dein klasse Beispiel, mk-soft.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8677
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von NicTheQuick »

Für Windows gibt es auch noch eine schöne Funktion, die alle ".." und "." auflöst:

Code: Alles auswählen

Procedure.s canonicalizePath(path.s)
	Protected newpath.s = Space(#MAX_PATH)
	If PathCanonicalize_(@newpath, @path)
		ProcedureReturn newpath
	EndIf
	ProcedureReturn ""
EndProcedure

Debug canonicalizePath("C:\Windows\system32\..\..\Program Files")
Damit könnte man notfalls auch noch arbeiten.
Bild
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Nino »

@mk-soft:
Schöner Code (funktioniert allerdings nur mit absoluten Pfaden).
Er kann noch etwas vereinfacht werden. :-)

Code: Alles auswählen

Procedure.s GetParentPath(Path.s, n.i=1)
   Protected i.i
   
   For i = 1 To n
      Path = GetPathPart(RTrim(Path, #PS$))
   Next
   
   ProcedureReturn Path
EndProcedure


Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\")
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 2)
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 3)
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 4)
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Nino »

Kurzer hat geschrieben:Wobei ich aber auch gemischte Path-Separatoren unterstützen wollte.
Dazu braucht man nur die If-Abfrage ein wenig zu ändern.
(Eine Prüfung mit If ist übrigens nicht nur hier in meiner Variante, sondern auch in mk-softs Original-Code nur 1x vor der Schleife nötig. Innerhalb der Schleife braucht man das nicht zu prüfen, weil da am Ende immer ein Pfadtrenner ist.)

Code: Alles auswählen

Procedure.s GetParentPath(Path.s, n.i=1)
   Protected i.i
   
   If FindString("\/", Right(Path, 1)) = 0
      Path + #PS$
   EndIf
   
   For i = 1 To n
      Path = GetPathPart(Left(Path, Len(Path)-1))
   Next
   
   ProcedureReturn Path
EndProcedure


Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\")
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 2)
Debug GetParentPath("D:/Obst/Äpfel/Reife/Greenstar/", 3)
Debug GetParentPath("D:\Obst\Äpfel\Reife\Greenstar\", 4)
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Sicro »

Im CodeArchiv habe ich dafür auch ein Include: GetParentDirectory.pbi
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
mk-soft
Beiträge: 3700
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von mk-soft »

Gemischter Path Separator ist eigentliche nicht erforderlich.
#PS$ liefert je nach OS den richtigen Separator.

@Nino
Mist... RTrim hatte ich vergessen :allright:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Nino »

mk-soft hat geschrieben:Gemischter Path Separator ist eigentliche nicht erforderlich.
#PS$ liefert je nach OS den richtigen Separator.
Ja, das schon. Und unter Linux funktioniert sowieso nur "/" als Pfadtrenner.
Aber unter Windows kann ein Pfad auch mal den falschen Pfadtrenner "/" enthalten, oder evtl. beide gemischt: "C:\Ein/Verzeichnis". Es kommt darauf an woher der Inhalt der Variable 'Pfad' stammt. Wenn es sich z.B. um eine Benutzereingabe handelt, weiß man vorher nie was da drin ist. :-)
mk-soft hat geschrieben:@Nino
Mist... RTrim hatte ich vergessen :allright:
:-)
Ja, dadurch wird der Code etwas kürzer. Allerdings käme es mir im Endeffekt darauf an, ob eine Variante deutlich schneller ist (habe das nicht getestet).
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Smarte Methode zum Dateipfad kürzen gesucht

Beitrag von Kurzer »

:allright:

Herzlichen Dank für eure weiteren Anregungen, Nino, Sicro und Nic.
Ich habe mich nun für diese Lösung entschieden die optional auch die Pfadseparatoren korrigert.

Code: Alles auswählen

Procedure.s GetParentPath(sPath.s, iLevelsUp.i = 1, sNewSeparator.s = "")
	Protected i.i, sOldSeparator.s = ""
	
	If FindString("\/", Right(sPath, 1)) = 0
		sPath + #PS$
	EndIf
	
	For i = 1 To iLevelsUp
		sPath = GetPathPart(Left(sPath, Len(sPath) - 1))
	Next
	
	Select sNewSeparator
		Case "\"
			sOldSeparator = "/" 
			ReplaceString(sPath, sOldSeparator, sNewSeparator, #PB_String_InPlace)
		Case "/"
			sOldSeparator = "\"
			ReplaceString(sPath, sOldSeparator, sNewSeparator, #PB_String_InPlace)
	EndSelect
	
	ProcedureReturn sPath
EndProcedure

Debug GetParentPath("D:\1\Obst/Äpfel\Reife/Greenstar",2, #PS$)
Debug GetParentPath("D:/2/Obst/Äpfel/Reife/Greenstar/",2, #PS$)
Debug GetParentPath("D:\3\Obst/Äpfel\Reife/Greenstar\", 3)
Debug GetParentPath("D:\4\Obst\Äpfel\Reife\Greenstar\", 3)
Debug GetParentPath("D:\5/Obst\Äpfel\Reife\Greenstar\")
Bei der Erstellung ist mir bzgl. ReplaceString() bei Benutzung des Parameters #PB_String_InPlace ein kurioses Verhalten aufgefallen.

Die Hilfe sagt zu dem Parameter:
Wenn diese Option verwendet wird, muss das Ergebnis von ReplaceString() ignoriert werden (und auch nirgends zugewiesen - da es der als Parameter übergebene 'String$' ist, der geändert wird).
Aber offenbar gibt ReplaceString() bei Verwendung von #PB_String_InPlace statt des übergebenen Strings einen alten Stringbuffer zurück, der bei der letzten Benutzung von ReplaceString() gefüllt wurde.

Code: Alles auswählen

Procedure.s ReturnString()
	Protected sText.s
	sText = "Eiscreme mit Erdbeersauce"
	sText = ReplaceString(sText, "Erd", "Brom")
	ProcedureReturn sText
EndProcedure

Debug ReturnString() ; Gibt 'Eiscreme mit Brombeersauce' aus
Debug ReplaceString("Hallo Welt", "Welt", "Mond", #PB_String_InPlace) ; Gibt ebenfalls 'Eiscreme mit Brombeersauce' aus!
Debug ReplaceString("Hallo Welt", "Welt", "Mond")                     ; Gibt 'Hallo Mond' aus
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Antworten