Mid$ Anweisung / Suchfunktion im Board

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Mid$ Anweisung / Suchfunktion im Board

Beitrag von Daffy0815 »

Hallo Leute,

mit einigem Erstaunen habe ich festgestellt, dass es in PureBasic offenbar keine Mid$-Anweisung gibt.
Mein Problem ist folgendes:

Ein String fester Länge (Kommandopuffer.s{20000}) wird mit Schleppzeigern Zeichenweise beschrieben / gelesen.

Das Lesen ist mit der MID-Funktion kein Problem aber wie positioniert man ein Zeichen in einem solchen String fester Länge.
Das Einzige was ich hierzu gefunden habe ist eine Prozedur die Strings "zusammenbastelt" was vermutlich irrsinnig langsam ist.

Auch würde mich interessieren warum die Suchfunktion im Board für "mid$", "mid$()" oder auch "mid" keine Ergebnisse liefert obwohl diese
Begriffe im Board enthalten sind.

Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
CSHW89
Beiträge: 489
Registriert: 14.12.2008 12:22

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von CSHW89 »

Zur Frage Mid$. Da du fixe Strings benutzt, ists kein Problem mit PokeC ein Zeichen zu ändern. Ungefähr so:

Code: Alles auswählen

Macro SetChar(_str_, _idx_, _char_)
  PokeC(@_str_+SizeOf(Character) * _idx_, _char_)
EndMacro

str.s{5}
str = "Hallo"
SetChar(str, 1, 'b')
Debug str
Zur Frage Suchfunktion. Anscheinend funktioniert die Suchfunktion mit Wörtern, deren Länge <= 3 ist, nicht, warum auch immer.

lg Kevin
Bild Bild Bild
http://www.jasik.de - Windows Hilfe Seite
padawan hat geschrieben:Ich liebe diese von hinten über die Brust ins Auge Lösungen
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von RSBasic »

Daffy0815 hat geschrieben:Auch würde mich interessieren warum die Suchfunktion im Board für "mid$", "mid$()" oder auch "mid" keine Ergebnisse liefert obwohl diese
Begriffe im Board enthalten sind.
Ganz einfach, weil du mind. 4 Zeichen eingeben musst. Ist standardmäßig so beim phpBB-Forum eingestellt. Und Sonderzeichen werden afaik ignoriert bzw. für andere Zwecke verwendet.
Wenn du nach kurzen Suchbegriffen suchen möchtest, dann nutze lieber Google: http://www.google.de/#sclient=psy-ab&hl ... rebasic.fr
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von hjbremer »

Code: Alles auswählen

Structure Zeichen
   c.c[0]
EndStructure

fixstring.s{100}

fixstring = "Dies ist ein String mit fester Zeichenlänge"

Debug fixstring

*c.zeichen = @fixstring

*c\c[3] = 65

Debug fixstring
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von Daffy0815 »

Vielen Dank für die Hilfe!

Habe die Lösung von CSHW89 verwendet weil sie mir "durchschaubarer" erscheint.
Allerdings habe ich beim Testen im Programm fast in die Tastatur gebissen!
Ich dachte das wenn man einen String fester Länge definiert dieser auch mit der angegebenen Länge angelegt wird.
Dem scheint aber nicht so zu sein.
Mein Pufferstring war immer leer.
Erst als ich diesen mit Zeichen gefüllt hatte stand da auch etwas drin.

Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
CSHW89
Beiträge: 489
Registriert: 14.12.2008 12:22

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von CSHW89 »

Lol, ich find die Lösung von hjbremer eigentlich viel eleganter als meine, würde diese also bevorzugen :lol: . Aber jedem das seine.

lg Kevin
Bild Bild Bild
http://www.jasik.de - Windows Hilfe Seite
padawan hat geschrieben:Ich liebe diese von hinten über die Brust ins Auge Lösungen
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

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von ts-soft »

CSHW89 hat geschrieben:Lol, ich find die Lösung von hjbremer eigentlich viel eleganter als meine, würde diese also bevorzugen :lol: . Aber jedem das seine.

lg Kevin
Ist auch schneller, aber ich denke das wird kaum messbar sein :mrgreen:
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
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von Daffy0815 »

@CSHW89

Also im Prinzip ist die Lösung von hjbremer doch die Gleiche nur das diese "C-mäßig" mit viel "kryptischen" Zeichen versehen ist.

Was passiert ist doch letztendlich nur:
1.) Startadresse des Strings im Speicher ermitteln
2.) Offset addieren
3.) Byte auf Adresse+Offset schreiben

Finde es aber nach wie vor armselig das PureBasic keine MID$-Anweisung eingebaut hat!

Das kann ja sogar mein 89C450-Microcontroller-BASIC seit 20 Jahren (Siehe folgende Zeilen aus dem Handbuch)

MID$() – eine Anweisung zur Zeichenkettenverarbeitung, die einen Teil einer
Zeichenkettenvariable durch eine andere Zeichenkette ersetzt.

Modus: Kommando oder Ablauf

Syntax:

MID$(Zeichenkettenvariable,Beginn[,Länge]) = Zeichenkettenausdruck

· Zeichenkettenvariable ist der Name der Variablen die verändert wird.
· Beginn ist ein numerischer Ausdruck im Bereich 1 bis 254 der die
Zeichenposition markiert ab der die Ersetzung beginnt.
· Länge ist ein numerischer Ausdruck im Bereich 1 bis 254 der die Anzahl
der Zeichen aus Zeichenkettenausdruck angibt mit denen ersetzt wird.
· Zeichenkettenausdruck ist Zeichenkettenkonstante, Zeichenkettenvariable
oder Zeichenkettenfunktion.

Beschreibung:
Die MID$-Anweisung wird zur Ersetzung von Zeichen in einer
Zeichenkettenvariablen durch Zeichen aus einem Zeichenkettenausdruck
verwendet. Ist Beginn größer als die Länge der Zeichenkettenvariable so bleibt
diese unverändert. Wird Länge nicht angegeben wird die Länge von
Zeichenkettenausdruck als Länge angenommen. Unabhängig von den für
Beginn und Länge gewählten Werten wird die Länge der
Zeichenkettenvariablen nicht geändert.

Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von mk-soft »

Selber basteln hilft...

Vielleicht so...

Code: Alles auswählen

Procedure.s SetMid(String$, StringToSet$, StartPos)
  
  Protected len1, len2, len3
  
  len1 = Len(String$)
  len2 = Len(StringToSet$)
  len3 = StartPos + len2
  If len1 < len3
    String$ + Space(len3 - len1)
  EndIf
  CopyMemory(@StringToSet$, @String$ + StartPos, len2)
  
  ProcedureReturn String$
  
EndProcedure

a$ = "Hallo unsere Welt ist an ende"
b$ = "unsere Erde"
a$ = SetMid(a$,b$, 6)
Debug a$
P.S.

oder so...
Update Unicode

Code: Alles auswählen

Procedure HelpSetMid(*String, *StringToSet, StartPos)
  
  Protected len1, len2, len3, *pos, *s1.String, *s2.String
  
  If StartPos < 1
    ProcedureReturn #False
  EndIf
  
  *s1 = @*String
  *s2 = @*StringToSet
  len1 = Len(*s1\s)
  len2 = Len(*s2\s)
  len3 = StartPos + len2
  If len1 < len3
    len2 = len1 - StartPos
    If len2 <= 0
      ProcedureReturn #False
    EndIf
  EndIf
  
  StartPos - 1
  
  CompilerIf #PB_Compiler_Unicode
    *pos = StartPos * SizeOf(character) + *String
    len2 = len2 * SizeOf(character)
  CompilerElse
    *pos = StartPos + *String
  CompilerEndIf
  
  CopyMemory(*StringToSet, *pos, len2)
  
  ProcedureReturn #True
  
EndProcedure

Macro SetMid(String, StringToSet, StartPos)
  HelpSetMid(@String, @StringToSet, StartPos)
EndMacro

Debug SizeOf(character)
a$ = "Hallo unsere Welt ist an ende"
b$ = "unsere Erde"
Debug SetMid(a$,b$,7)
Debug a$
FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Mid$ Anweisung / Suchfunktion im Board

Beitrag von Daffy0815 »

Hallo Leute,

also irgendetwas stimmt mit der Stringverarbeitung in PureBasic nicht!

Um das zu verdeutlichen habe ich mal 3 lauffähige Beispiele gemacht.

Zum Testen muss über die definierte serielle Schnittstelle (COM1) alle 5 Sekunden die Zeichenkette "DI25=123456<CR>" gesendet werden.
Die empfangene Zeichenkette wird jeweils im Debug-Fenster ausgegeben.

Beispiel 1 ist mit der Variante von CSHW89 realisiert.
Beispiel 2 ist mit der Variante von hjbremer realisiert.
Diese beiden Beispiele verhalten sich völlig gleich.
Irgendwann ist ein empfangenes Zeichen im String nicht mehr vorhanden.

Beispiel 3 ist vom Aufbau her völlig gleich nur das für den Ringpuffer kein String fester Länge sondern ein mit "DIM" dimensioniertes ASCII-Feld verwendet wird.
Und das funktioniert bei gleicher Struktur EINWANDFREI!!!

Würde mich mal interessieren ob ihr den Grund hierfür herausbekommt.

Beispiel 1:

Code: Alles auswählen

#SerialportPLC = 0
#SerialportBaudratePLC = 115200
Global SerialPortNamePLC$ = "COM1"
;
;
#LaengeRegisterKommandoRingpuffer = 30 ;20000
Global RegisterKommandoRingpufferSchreibzeiger.u = 1
Global RegisterKommandoRingpufferLesezeiger.u = 1
Global RegisterKommandoRingpuffer.s{#LaengeRegisterKommandoRingpuffer+1} = Space(#LaengeRegisterKommandoRingpuffer)
Global RegisterKommandoPuffer.s
;
;
Procedure IncRegisterKommandoRingpufferSchreibzeiger()
    RegisterKommandoRingpufferSchreibzeiger.u = RegisterKommandoRingpufferSchreibzeiger.u + 1
    If RegisterKommandoRingpufferSchreibzeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferSchreibzeiger.u = 1
    EndIf
EndProcedure
;
;
Procedure IncRegisterKommandoRingpufferLesezeiger()
    RegisterKommandoRingpufferLesezeiger.u = RegisterKommandoRingpufferLesezeiger.u + 1
    If RegisterKommandoRingpufferLesezeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferLesezeiger.u = 1
    EndIf
EndProcedure
;
;
Macro SetChar(_str_, _idx_, _char_)
    PokeC(@_str_+SizeOf(Character) * _idx_, _char_)
EndMacro
;
;
Procedure RegisterEmpfang()
    Puffer.b = 0
    RegisterEmpfangen.i = #False
    If IsSerialport(#SerialportPLC)
        While AvailableSerialPortInput(#SerialportPLC) > 0
            ReadSerialPortData(#SerialportPLC, @Puffer.b, 1)
            EmpfangenesZeichen.s = Chr(Puffer.b)
            SetChar(RegisterKommandoRingpuffer.s, RegisterKommandoRingpufferSchreibzeiger.u, Puffer.b)
            IncRegisterKommandoRingpufferSchreibzeiger()
            If Puffer.b = 13
                 RegisterEmpfangen.i = #True
                 Break
            EndIf
        Wend
        If RegisterEmpfangen.i = #True
            RegisterKommandoPuffer.s = ""
            While RegisterKommandoRingpufferLesezeiger.u <> RegisterKommandoRingpufferSchreibzeiger.u
                RegisterKommandoPuffer.s = RegisterKommandoPuffer.s + Mid(RegisterKommandoRingpuffer.s, RegisterKommandoRingpufferLesezeiger.u, 1)
                IncRegisterKommandoRingpufferLesezeiger()
            Wend
            Debug RegisterKommandoPuffer.s            
        EndIf
    EndIf
EndProcedure


If OpenSerialPort(#SerialportPLC, SerialPortNamePLC$, #SerialportBaudratePLC, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)
    SetSerialPortStatus(#SerialportPLC, #PB_SerialPort_DTR, 0)
EndIf

Quit.i = #False
Repeat
    RegisterEmpfang()
    ;
Until Quit.i = #True

Beispiel 2:

Code: Alles auswählen

#SerialportPLC = 0
#SerialportBaudratePLC = 115200
Global SerialPortNamePLC$ = "COM1"
;
;
#LaengeRegisterKommandoRingpuffer = 30 ;20000
Global RegisterKommandoRingpufferSchreibzeiger.u = 1
Global RegisterKommandoRingpufferLesezeiger.u = 1
Global RegisterKommandoRingpuffer.s{#LaengeRegisterKommandoRingpuffer+1} = Space(#LaengeRegisterKommandoRingpuffer)
Global RegisterKommandoPuffer.s
;
;
Procedure IncRegisterKommandoRingpufferSchreibzeiger()
    RegisterKommandoRingpufferSchreibzeiger.u = RegisterKommandoRingpufferSchreibzeiger.u + 1
    If RegisterKommandoRingpufferSchreibzeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferSchreibzeiger.u = 1
    EndIf
EndProcedure
;
;
Procedure IncRegisterKommandoRingpufferLesezeiger()
    RegisterKommandoRingpufferLesezeiger.u = RegisterKommandoRingpufferLesezeiger.u + 1
    If RegisterKommandoRingpufferLesezeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferLesezeiger.u = 1
    EndIf
EndProcedure
;
;
Procedure RegisterEmpfang()
    Structure Zeichen
       c.c[0]
    EndStructure    
    ;
    Puffer.b = 0
    RegisterEmpfangen.i = #False
    If IsSerialport(#SerialportPLC)
        While AvailableSerialPortInput(#SerialportPLC) > 0
            ReadSerialPortData(#SerialportPLC, @Puffer.b, 1)
            EmpfangenesZeichen.s = Chr(Puffer.b)
            *c.zeichen = @RegisterKommandoRingpuffer.s
            *c\c[RegisterKommandoRingpufferSchreibzeiger.u] = Puffer.b
            IncRegisterKommandoRingpufferSchreibzeiger()
            If Puffer.b = 13
                 RegisterEmpfangen.i = #True
                 Break
            EndIf
        Wend
        If RegisterEmpfangen.i = #True
            RegisterKommandoPuffer.s = ""
            While RegisterKommandoRingpufferLesezeiger.u <> RegisterKommandoRingpufferSchreibzeiger.u
                RegisterKommandoPuffer.s = RegisterKommandoPuffer.s + Mid(RegisterKommandoRingpuffer.s, RegisterKommandoRingpufferLesezeiger.u, 1)
                IncRegisterKommandoRingpufferLesezeiger()
            Wend
            Debug RegisterKommandoPuffer.s            
        EndIf
    EndIf
EndProcedure


If OpenSerialPort(#SerialportPLC, SerialPortNamePLC$, #SerialportBaudratePLC, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)
    SetSerialPortStatus(#SerialportPLC, #PB_SerialPort_DTR, 0)
EndIf

Quit.i = #False
Repeat
    RegisterEmpfang()
    ;
Until Quit.i = #True
Beispiel 3:

Code: Alles auswählen

#SerialportPLC = 0
#SerialportBaudratePLC = 115200
Global SerialPortNamePLC$ = "COM1"
;
;
#LaengeRegisterKommandoRingpuffer = 30 ;20000
Global RegisterKommandoRingpufferSchreibzeiger.u = 0
Global RegisterKommandoRingpufferLesezeiger.u = 0
Global Dim RegisterKommandoRingpuffer.a(#LaengeRegisterKommandoRingpuffer+1)
Global RegisterKommandoPuffer.s
;
;
;Hilfsprozeduren
;
Procedure IncRegisterKommandoRingpufferSchreibzeiger()
    RegisterKommandoRingpufferSchreibzeiger.u = RegisterKommandoRingpufferSchreibzeiger.u + 1
    If RegisterKommandoRingpufferSchreibzeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferSchreibzeiger.u = 0
    EndIf
EndProcedure
;
;
Procedure IncRegisterKommandoRingpufferLesezeiger()
    RegisterKommandoRingpufferLesezeiger.u = RegisterKommandoRingpufferLesezeiger.u + 1
    If RegisterKommandoRingpufferLesezeiger.u > #LaengeRegisterKommandoRingpuffer
        RegisterKommandoRingpufferLesezeiger.u = 0
    EndIf
EndProcedure
;
;
Procedure RegisterEmpfang()
    Puffer.a = 0
    RegisterEmpfangen.i = #False
    If IsSerialport(#SerialportPLC)
        While AvailableSerialPortInput(#SerialportPLC) > 0
            ReadSerialPortData(#SerialportPLC, @Puffer.a, 1)
            RegisterKommandoRingpuffer.a(RegisterKommandoRingpufferSchreibzeiger.u) = Puffer.a
            IncRegisterKommandoRingpufferSchreibzeiger()
            If Puffer.a = 13
                 RegisterEmpfangen.i = #True
                 Break
            EndIf
        Wend
        If RegisterEmpfangen.i = #True
            RegisterKommandoPuffer.s = ""
            While RegisterKommandoRingpufferLesezeiger.u <> RegisterKommandoRingpufferSchreibzeiger.u
                RegisterKommandoPuffer.s = RegisterKommandoPuffer.s + Chr(RegisterKommandoRingpuffer.a(RegisterKommandoRingpufferLesezeiger.u))
                IncRegisterKommandoRingpufferLesezeiger()
            Wend
            Debug RegisterKommandoPuffer.s            
        EndIf
    EndIf
EndProcedure


If OpenSerialPort(#SerialportPLC, SerialPortNamePLC$, #SerialportBaudratePLC, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)
    SetSerialPortStatus(#SerialportPLC, #PB_SerialPort_DTR, 0)
EndIf

Quit.i = #False
Repeat
    RegisterEmpfang()
    ;
Until Quit.i = #True

Gruß
Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Gesperrt