Escape Sequenzen

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Escape Sequenzen

Beitrag von ts-soft »

Code: Alles auswählen

Procedure.s EscapeString(string.s)
  Protected term.c = 0, ende.l = 0
  Protected *c.Character = @string

  While *c\c ! 0
    If *c\c = '\'
      *c\c = term
    EndIf
    *c + SizeOf(Character)
  Wend

  ende = *c
  *c   = @string

  While *c ! ende
    If *c\c = term
      *c + SizeOf(Character)
      Select *c\c
        Case term : *c\c = '\'
        Case 'a'  : *c\c =  7 ; bel
        Case 'b'  : *c\c =  8 ; backspace
        Case 't'  : *c\c =  9 ; Tab
        Case 'l'  : *c\c = 10 ; linefeed
        Case 'f'  : *c\c = 12 ; formfeed
        Case 'r'  : *c\c = 13 ; return
        Case 'n'              ; carriage return
          *c - SizeOf(Character)
          *c\c = 13
          *c + SizeOf(Character)
          *c\c = 10
        Case 'q'  : *c\c = 34 ; dquote
      EndSelect
    EndIf
    *c + SizeOf(Character)
  Wend

  *c = @string

  While *c ! ende
    If *c\c = 0
      CopyMemory(*c + SizeOf(Character), *c, ende - *c)
    EndIf
    *c + SizeOf(Character)
  Wend

  ProcedureReturn string
EndProcedure

Macro esc(string) ; user defined
  EscapeString(string)
EndMacro

MessageRequester("", esc("*\tHello\t\t*\n*\tThere!\t\t*"))
MessageRequester("", esc("C:\\Program Files\\PureBasic\\"))
MessageRequester("", esc("\qTest in Dquote\q"))
MessageRequester("", esc( "\\no problems ?"))

Idee entstand durch diesen Thread: http://www.purebasic.fr/english/viewtopic.php?t=25684
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Dank der Mithilfe von edel konnte obige Procedure noch verbessert werden.
Als term wird immer Chr(0) verwendet statt des "|" Pipe-Zeichens, da dieses
Zeichen niemals in PB Strings vorkommt, deshalb wurden auch die
ReplaceString Funktionen durch PB-Code ersetzt, da diese Chr(0) ebenfalls
nicht unterstützen. Insgesamt ist die Procedure dadurch mehr als doppelt so
schnell geworden.

Gruß
Thomas

// Nachtrag:
Jedes Backslash "\" muß eine gültige EscapeSequenz sein, sonst gibts nen "Invalide Memory Access"
Escape Sequenzen sind:

Code: Alles auswählen

\\ = \
\a = bell (Glocke)
\b = Backspace
\t = Tab
\l = LineFeed (Zeilenvorschub) #LF$
\f = FormFeed
\r = Return #CR$
\n = CarriageReturn #CRLF$
\q = DQuote (Anführungszeichen)
Alle hier nicht aufgeführten Kombinationen z.B. \P sind ungültig und
dürfen nicht vorkommen, ersatz wäre \\P

Ähnliche EscapeSequenzen gibts in den meisten Programmiersprache wie
Java, C, Profan usw.
Damit kann man sich die ganzen "bla" + #DQUOTE$ + " usw." sparen
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

Beitrag von Leonhard »

Danke, ich kann das gut gebrauchen.

Ich hab hier noch ne kleine erweiterung gebastelt: man kann jetzt eine Liste mit neuen EscapeSequenzen angeben.

Code: Alles auswählen

Macro NewArray(StructureName, Elements)
  AllocateMemory(SizeOf(StructureName)*(Elements+1))
EndMacro
Macro FreeArray(ArrayPointer)
  FreeMemory(ArrayPointer)
EndMacro
Macro GetArrayElement(ArrayPointer, StructureName, Element)
  ArrayPointer+(SizeOf(StructureName)*Element)
EndMacro
Structure EscapeString_Array
  cSearch .c ;/ Das Zeichen, das nach '\' erwartet wird.
  cReplace.c ;/ Das Zeichen, das ersetzt wird.
EndStructure

Procedure.s EscapeString(string.s, *Array = #Null, ArrayLen = 0)
  Protected term.c = 0, ende.l = 0
  Protected *c.Character = @string
  Protected *ArrayItem.EscapeString_Array, i.l
  
  While *c\c ! 0
    If *c\c = '\'
      *c\c = term
    EndIf
    *c + SizeOf(Character)
  Wend
  
  ende = *c
  *c   = @string
  
  While *c ! ende
    If *c\c = term
      *c + SizeOf(Character)
      Select *c\c
        Case term : *c\c = '\'
        Case 'a'  : *c\c =  7 ; bel
        Case 'b'  : *c\c =  8 ; backspace
        Case 't'  : *c\c =  9 ; Tab
        Case 'l'  : *c\c = 10 ; linefeed
        Case 'f'  : *c\c = 12 ; formfeed
        Case 'r'  : *c\c = 13 ; return
        Case 'n'              ; carriage return
          *c - SizeOf(Character)
          *c\c = 13
          *c + SizeOf(Character)
          *c\c = 10
        Case 'q'  : *c\c = 34 ; dquote
        Default
          If *Array
            For i = 0 To ArrayLen - 1
              *ArrayItem = GetArrayElement(*Array, EscapeString_Array, i)
              If *ArrayItem\cSearch = *c\c
                *c\c = *ArrayItem\cReplace
                
                Break
              EndIf
            Next i
          EndIf
      EndSelect
    EndIf
    *c + SizeOf(Character)
  Wend
  
  *c = @string
  
  While *c ! ende
    If *c\c = 0
      CopyMemory(*c + SizeOf(Character), *c, ende - *c)
    EndIf
    *c + SizeOf(Character)
  Wend
  
  ProcedureReturn string
EndProcedure

Macro esc(string, Array = #Null, ArrayLen = 0) ; user defined
  EscapeString(string, Array, ArrayLen)
EndMacro

Debug esc("*\tHello\t\t*\n*\tThere!\t\t*")
Debug esc("*\tHello\t\t*\n*\tThere!\t\t*")
Debug esc("C:\\Program Files\\PureBasic\\")
Debug esc("\qTest in Dquote\q")
Debug esc("\\no problems ?")

Define *Array = NewArray(EscapeString_Array, 1)
Define *ArrayItem.EscapeString_Array = GetArrayElement(*Array, EscapeString_Array, 0)
With *ArrayItem
  \cSearch  = 's'
  \cReplace = '.'
EndWith

Debug esc("Test with arrays\s", *Array, 1)

FreeArray(*Array)

End
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Nette Idee, wäre mir aber zu Aufwendig, da füg ich lieber eine Zeile im
Selekt ein.
Freud mich, wenns tatsächlich jemand ausser mir nutzt :allright:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
helpy
Beiträge: 636
Registriert: 29.08.2004 13:29

Beitrag von helpy »

Hier meine noch etwas erweiterte Version (die oben angeführten Versionen hatte ich erst später entdeckt):

Code: Alles auswählen

CompilerIf #PB_Compiler_Unicode = #False
	CompilerError "The function CString can only be used in unicode mode!"
CompilerEndIf

; Angelehnt an http://de.wikipedia.org/wiki/Escape-Sequenz:
; -----------------------------------------------------------------------------
; \'      Einfaches Anführungszeichen
;         ==> Habe ich nicht extra eingebaut, und wird behandelt 
;             wie alle anderen "unbehandelten Escape-Zeichen".
; \"      Doppeltes Anführungszeichen
;         ==> Ist in PureBasic nicht möglich!
; \\      umgekehrter Schrägstrich
; \0      Nullzeichen (NUL, nicht das Zahlzeichen "0")
; \a      akustisches Signal (von englisch alert)
; \b      Rückschritt (von englisch backspace)
; \f      Seitenvorschub (von englisch formfeed)
; \n      Zeilenumbruch (von englisch new line)
; \r      Wagenrücklauf (von englisch (carriage) Return)
; \t      Horizontaler Tabulator (von englisch (horizontal) tabulator)
; \v      Vertikaler Tabulator (von englisch vertical tabulator)
; \xhh    Direkte Zeichenauswahl durch zwei folgende Hexadezimalziffern hh
;         ('A' entspricht '\x41') (von hexadezimal)
;         ==> \x22 kann für ein doppeltes Anführungszeichen verwendet werden
; \ooo    Direkte Zeichenauswahl durch folgende maximal drei Oktalziffern ooo
;         ('A' entspricht '\101')
;         ==> \0 ist  ein Spezialfall dieser Regel
;         ==> \42 kann für ein doppeltes Anführungszeichen verwendet werden
; \uhhhh  Start einer Unicode-Zeichensequenz; auf diese müssen vier 
;         Hexadezimalziffern hhhh folgen
;         (z.B. steht \u20ac für das Euro-Symbol) (von Unicode)
; -----------------------------------------------------------------------------
; \.      Alle anderen Zeichen stellen das Zeichen selbst dar!
; -----------------------------------------------------------------------------
; Es gibt verschiedene Definitionen von Escape-Sequenzen. Bei einigen ist
; z.B. die Anzahl der hexadezimalen Ziffern nach \x.. variabel. Ich habe 
; die Variante mit 2 festen Ziffern gewählt.
; -----------------------------------------------------------------------------

; Fügt ein Zeichen zum String hinzu und erhöht den Zähler
Macro CString__ADD(CharPointer,charCode)
	CharPointer\c = charCode : CharPointer + SizeOf(Character)
EndMacro

; Konvertiere Hexadezimal nach Dezimal.
; Der Wert wird als Zeichen (Character) zurückgegeben
Procedure.c CString__HexToChar(hex.s)
	Protected *h.Character
	Protected dec.l
	hex = UCase(hex)
	*h = @hex
	While *h\c <> 0
		If *h\c > '9'
			*h\c - 'A' + 10
		Else
			*h\c - '0'
		EndIf
		dec = (dec << 4) + *h\c
		*h + SizeOf(Character)
	Wend
	ProcedureReturn (dec & $FFFF)
EndProcedure

; Konvertiere Octal nach Dezimal.
; Der Wert wird als Zeichen (Character) zurückgegeben
Procedure.c CString__OctToChar(oct.s)
	Protected *o.Character
	Protected dec.l
	*o = @oct
	While *o\c <> 0
		*o\c - '0'
		dec = (dec << 3) + *o\c
		*o + SizeOf(Character)
	Wend
	ProcedureReturn (dec & $FFFF)
EndProcedure

; Enumaeration für die Konvertierung des C-Strings
Enumeration
	#char_NORMAL
	#char_ESC_SEQUENCE
	#char_OCTAL
	#char_HEX
	#char_UNICODE
EndEnumeration
Procedure.s CString(CString.s)
	Protected *cchar.Character = @CString
	Protected PBString.s = Space(Len(CString))
	Protected *pchar.Character = @PBString
	Protected charType.l = #char_NORMAL
	Protected numCount.l
	Protected numValue.l
	Protected numBuffer.s
	Protected *c.Character
	
	While *cchar\c <> 0
		Select charType 

			Case #char_NORMAL
				Select *cchar\c
					Case '\' ; Start der Escape-Sequenz
						charType = #char_ESC_SEQUENCE
					Default
						CString__ADD(*pchar, *cchar\c)
				EndSelect
			
			Case #char_ESC_SEQUENCE
				charType = #char_NORMAL
				Select *cchar\c
					Case 'a' : CString__ADD(*pchar, #BEL)
					Case 'b' : CString__ADD(*pchar, #BS)
					Case 't' : CString__ADD(*pchar, #TAB)
					Case 'n' : CString__ADD(*pchar, #LF)
					Case 'v' : CString__ADD(*pchar, #VT)
					Case 'f' : CString__ADD(*pchar, #FF)
					Case 'r' : CString__ADD(*pchar, #CR)
					Case '\' : CString__ADD(*pchar, '\')
					Case 'x'
						charType = #char_HEX
						numCount = 2 
						numValue = 0
						numBuffer = ""
					Case 'u'
						charType = #char_UNICODE
						numCount = 4
						numValue = 0
						numBuffer = ""
					Case '0' To '7'
						charType = #char_OCTAL
						numCount = 2
						numValue = 0
						numBuffer = Chr(*cchar\c)
					Default ; Einzelnes \ mit unbekanntem Buchstaben/Ziffer
						CString__ADD(*pchar,*cchar\c)
				EndSelect

			Case #char_OCTAL
				Select *cchar\c
					Case '0' To '7'
						numBuffer + Chr(*cchar\c)
						numCount - 1
						If numCount = 0
							charType = #char_NORMAL
							CString__ADD(*pchar, CString__OctToChar(numBuffer))
						EndIf
					Default
						charType = #char_NORMAL
						CString__ADD(*pchar, CString__OctToChar(numBuffer))
				EndSelect

			Case #char_HEX
				numBuffer + Chr(*cchar\c)
				Select *cchar\c
					Case '0' To '9', 'a' To 'f', 'A' To 'F'
						numCount - 1
						If numCount = 0
							charType = #char_NORMAL
							CString__ADD(*pchar, CString__HexToChar(numBuffer))
						EndIf
					Default ; Wenn nach dem \x nicht 2 Hex-Ziffern kommen,
					         ; wird statt "\x" das Zeichen "x" ausgegeben
						CString__ADD(*pchar, 'x')
						*c = @numBuffer
						While *c\c <> 0
							CString__ADD(*pchar, *c\c)
							*c + SizeOf(Character)
						Wend
						charType = #char_NORMAL
				EndSelect

			Case #char_UNICODE
				numBuffer + Chr(*cchar\c)
				Select *cchar\c
					Case '0' To '9', 'a' To 'f', 'A' To 'F'
						numCount - 1
						If numCount = 0
							charType = #char_NORMAL
							CString__ADD(*pchar, CString__HexToChar(numBuffer))
						EndIf
					Default ; Wenn nach dem \u nicht 4 Hex-Ziffern kommen,
					         ; wird statt "\u" das Zeichen "u" ausgegeben
						CString__ADD(*pchar, 'u')
						*c = @numBuffer
						While *c\c <> 0
							CString__ADD(*pchar, *c\c)
							*c + SizeOf(Character)
						Wend
						charType = #char_NORMAL
				EndSelect

		EndSelect
		*cchar + SizeOf(Character)		
	Wend
	
	*pchar\c = #NUL

	ProcedureReturn PBString
EndProcedure
Da ich das ganze nur im Unicode-Modus verwende, habe ich die Compiler-Bedingung eingebaut. Wer es für den ASCII/ANSI Modus (8-Bit Zeichen) benötigt, der muss sich das entsprechend anpassen.

cu, guido
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Escape Sequenzen

Beitrag von NicTheQuick »

Das hat nicht zufällig jemand schonmal für die andere Richtung programmiert? Dann muss ich das nicht machen. :D

Ich brauche das unter Linux, weil manche Programme anscheinend unbedingt einen Escaped String als Parameter erwarten. Einfache Anführungszeichen vor und hinter dem zu übergebenden Parameter reichen scheinbar nicht.

Aus "Ainda samba FS BB WM listen 2.wav" soll dann "Ainda\ samba\ -\ FS\ BB\ WM\ listen\ 2.wav" werden.

///Edit:
Zu spät...
Das hier reicht mir schon:

Code: Alles auswählen

Procedure.s escapedString(s.s)
	Protected escaped.s, *c.Character = @s
	
	While *c\c
		Select *c\c
			Case ' ':	escaped + "\ "
			Case 7:		escaped + "\a"
			Case 8:		escaped + "\b"
			Case 9:		escaped + "\t"
			Case 10:	escaped + "\n"	
			Case 12:	escaped + "\f"
			Case 13:	escaped + "\r"
			Case 39:	escaped + "\'"
			Case '"':	escaped + "\" + Chr(34)
			Case '?':	escaped + "\?"
			Case '\':	escaped + "\\"
			Default:
				escaped + Chr(*c\c)
		EndSelect
		*c + SizeOf(Character)
	Wend
	
	ProcedureReturn escaped
EndProcedure
///Edit:
Jetzt brauche ich die Funktion doch nicht mehr. Naja, ihr könnt sie trotzdem behalten. Ich bin heute wieder so gütig! :mrgreen:
Benutzeravatar
bobobo
jaAdmin
Beiträge: 3873
Registriert: 13.09.2004 17:48
Kontaktdaten:

Re: Escape Sequenzen

Beitrag von bobobo »

ömm

Code: Alles auswählen

MessageRequester("", esc("C:\\\Program Files\\\PureBasic\\\"))
in ganz obigem code macht dummes zeug genau wie alle sich selbst in ungeraden anzahlen folgenden \ (zumindest die vor dem ")
‮pb aktuel 6.2 windoof aktuell und sowas von 10
Ich hab Tinnitus im Auge. Ich seh nur Pfeifen.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Escape Sequenzen

Beitrag von PureLust »

ömm
bobobo hat geschrieben:... in ganz obigem code macht dummes zeug genau wie alle sich selbst in ungeraden anzahlen folgenden \ (zumindest die vor dem ")
Biddö was? Ist doch erst Mittag ... und schon einen gepichelt? :mrgreen: *hicks*
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
bobobo
jaAdmin
Beiträge: 3873
Registriert: 13.09.2004 17:48
Kontaktdaten:

Re: Escape Sequenzen

Beitrag von bobobo »

weder (mittag) noch (gepishelt)

stell es dir einfach mal (alles, nebst codeblock) hintereinander geschrieben vor
‮pb aktuel 6.2 windoof aktuell und sowas von 10
Ich hab Tinnitus im Auge. Ich seh nur Pfeifen.
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

Re: Escape Sequenzen

Beitrag von Bisonte »

den find ich jetzt erst.... :allright:

Gut zu gebrauchen in Verbindung mit dem PB Interpreter ;)
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Antworten