SCL Stringzerlegung

merlin

Level-1
Beiträge
184
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo

Ich bekomme aus einer Presse einen verketteten Ergebnissstring:
"123.4$r$l3456.78$r$l-T -Z"

Die Trennzeichen ($r$l) können an ihrer Position variieren je nachdem wieviele Stellen die Zahle davor hat.
Ich muss nun den verketteten String so zerlegen, das am Ende die Einzelnen Zahlen in REAL ausgegeben werden und der letzte Block als String.

Ich hätte an SCL gedacht bin aber auf SCL absoluter Neuling. Kann mir da wer weiterhefen?

Besten Dank
Thomas
 
du findest alle hierzu nötigen bausteine in der open source library oscat
die funktion find_nun and find_nonum dienen dazu zahlen und nicht zahlenzeichen zu suchen.
die lib kannst du downloaden unter www.oscat.lib
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Oh das macht keinen Spaß ;o(

Ich habe eben mal kurz versucht was zu bauen und bin über das $ gestolpert das ist bei den String-Konstanten ein Escape Zeichen und und hat mein Experiment vereitelt. Aber ansich ist die Aufgabe nicht wild. Kannst auch in der Hilfe von SCL unter FIND, LEN, LEFT, RIGHT nachlesen.
 
Hallo,
ich hoffe das zumindestens Grundkenntnisse vorhanden sind.

Du brauchst dafür nicht die Oscat-Lib, Siemens kann das alles auch ...
Ich würde grundsätzlich so vorgehen:
Hilfs-Strings für den Gesamt-String und alle Teil-Variablen anlegen.
Quell-String in Hilfs-String 1 kopieren.
Diesen mittels FIND nach dem 1. "$"-Zeichen durchsuchen.
Ab der zurück-gelieferten Position den linken Teil des Strings mit LEFT abschneiden und in die 1. Teil-Variable kopieren und den rechten Teil des Strings in eine neue Hilfs-Variable kopieren.
Mit dieser dann verfahren wie vorher ...

Das ist auf jeden Fall ein bißchen Probiererei, aber durchaus zu schaffen ...

Gruß
LL
 
rechten Teil des Strings in eine neue Hilfs-Variable kopieren.
Mit dieser dann verfahren wie vorher ...
nicht ganz. das erste zeichen ist dann ja das $.
also 4 zeichen später beginnen (gibts unter scl mid ? )bzw right(reststring,stringlaenge-4)
 
Also ich stell mal einen Ansatz hier rein.

Ich behaupte nicht das es der einfachste Weg ist und an den kniffligen Stellen fehlen auch noch Kommentare ;o( Aber gerade das Wandeln von STRING nach Real habe ich mit den Step7 Boardmitteln auf die Schnelle nicht besser hinbekommen.

Code:
FUNCTION FC10 : VOID
VAR_INPUT
  S             :STRING[40];
  Token         :STRING[5];
END_VAR

VAR_OUTPUT
  T1_real       :REAL;
  T2_real       :REAL;
  T3_string     :STRING[40];
END_VAR

VAR_TEMP
  myString      :STRING[40];
  myToken       :STRING[5];
  myPos         :INT;
  myTeil_1      :STRING[40];
  myTeil_2      :STRING[40];
  myTeil_3      :STRING[40];  
  myINT_1       :INT;  
  myINT_2       :INT;    
END_VAR
  (* Strings Initialisieren *)
  myString      :='';
  myToken       :='';
  myTeil_1      :='';
  myTeil_2      :='';
  myTeil_3      :='';

  (* Eingangs Variablen in Temp Kopieren *)
  myString := S;      //'555.4_r_l3456.78_r_l-T -Z';
  myToken  := Token;  //'_r_l';

  (* Erste Zahl ausschneiden / String *)
  myPos := FIND(IN1:=myString, IN2:=myToken);
  myTeil_1 := LEFT(IN:=myString, L:=myPos - 1);  
  
  myString := RIGHT(IN:=myString, L:=LEN(myString) - myPos - LEN(S:=myToken) + 1);

  (* Erste Zahl ausschneiden / String *)
  myPos := FIND(IN1:=myString, IN2:=myToken);
  myTeil_2 := LEFT(IN:=myString, L:=myPos - 1);  

  (* Rest des Strings Abschneiden *)
  myTeil_3 := RIGHT(IN:=myString, L:=LEN(myString) - myPos - LEN(S:=myToken) + 1);  
  T3_string := myTeil_3;
  
  (* Erste Zahl *)
  (* Teil vor dem Dezimalpunkt Kopieren und in INT wandeln *)
  myPos := FIND(IN1:=myTeil_1, IN2:='.');
  myString := LEFT(IN:=myTeil_1, L:=myPos - 1);  
  myINT_1 := STRNG_I(myString);
  (* Teil nach dem Dezimalpunkt Kopieren und in INT wandeln *)
  myString := RIGHT(IN:=myTeil_1, L:= LEN(myTeil_1) - myPos);  
  myINT_2 := STRNG_I(myString);
  (* Aus den zwei INT teilen einen Real basteln *)
  T1_real := ((INT_TO_REAL(myINT_1) * EXPD(LEN(myString)))  +  INT_TO_REAL(myINT_2)) / EXPD(LEN(myString)) ;

  (* Zweite Zahl *)
  (* Teil vor dem Dezimalpunkt Kopieren und in INT wandeln *)
  myPos := FIND(IN1:=myTeil_2, IN2:='.');
  myString := LEFT(IN:=myTeil_2, L:=myPos - 1);  
  myINT_1 := STRNG_I(myString);
  (* Teil nach dem Dezimalpunkt Kopieren und in INT wandeln *)
  myString := RIGHT(IN:=myTeil_2, L:= LEN(myTeil_2) - myPos);  
  myINT_2 := STRNG_I(myString);
  (* Aus den zwei INT teilen einen Real basteln *)  
  T2_real := ((INT_TO_REAL(myINT_1) * EXPD(LEN(myString)))  +  INT_TO_REAL(myINT_2)) / EXPD(LEN(myString)) ;
END_FUNCTION
 
Hallo,

bin gerade auf den Thread gestoßen, um ihn für Nachfolgende zu vervollständigen:

Aber gerade das Wandeln von STRING nach Real habe ich mit den Step7 Boardmitteln auf die Schnelle nicht besser hinbekommen.

IEC-Standardfunktionen für STRING-Variable:
Mit den IEC-Standardfunktionen FC5, FC16, FC30, FC37, FC38 und FC39 können Sie Variablen im DINT-Format in eine Zeichenkette und umgekehrt umwandeln.
  1. FC5 DI_STRNG: Umwandlung einer Variable vom Typ DINT in eine Variable vom Typ STRING,
  2. FC16 I_STRNG: Umwandlung einer Variable vom Typ INT in eine Variable vom Typ STRING,
  3. FC30 R_STRNG: Umwandlung einer Variable vom Typ REAL in eine Variable vom Typ STRING,
  4. FC37 STRNG_DI: Umwandlung einer STRING-Variablen in eine Variable vom Typ DINT,
  5. FC38 STRNG_I: Umwandlung einer STRING-Variablen in eine Variable vom Typ INT,
  6. FC39 STRNG_R: Umwandlung einer STRING-Variablen in eine Variable vom Typ REAL.
Weitere Informationen finden Sie auch in unserem Beitrag "Welche Standardfunktionen von STEP 7 gibt es bezüglich Umwandlung und Vergleich von STRING-Variablen bzw. ASCII-Zeichen?" unter der Beitrags-ID: 10913338.


Grüße
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also ich stell mal einen Ansatz hier rein.

Ich behaupte nicht das es der einfachste Weg ist und an den kniffligen Stellen fehlen auch noch Kommentare ;o( Aber gerade das Wandeln von STRING nach Real habe ich mit den Step7 Boardmitteln auf die Schnelle nicht besser hinbekommen.

Code:
FUNCTION FC10 : VOID
VAR_INPUT
  S             :STRING[40];
  Token         :STRING[5];
END_VAR

VAR_OUTPUT
  T1_real       :REAL;
  T2_real       :REAL;
  T3_string     :STRING[40];
END_VAR

VAR_TEMP
  myString      :STRING[40];
  myToken       :STRING[5];
  myPos         :INT;
  myTeil_1      :STRING[40];
  myTeil_2      :STRING[40];
  myTeil_3      :STRING[40];  
  myINT_1       :INT;  
  myINT_2       :INT;    
END_VAR
  (* Strings Initialisieren *)
  myString      :='';
  myToken       :='';
  myTeil_1      :='';
  myTeil_2      :='';
  myTeil_3      :='';

  (* Eingangs Variablen in Temp Kopieren *)
  myString := S;      //'555.4_r_l3456.78_r_l-T -Z';
  myToken  := Token;  //'_r_l';

  (* Erste Zahl ausschneiden / String *)
  myPos := FIND(IN1:=myString, IN2:=myToken);
  myTeil_1 := LEFT(IN:=myString, L:=myPos - 1);  
  
  myString := RIGHT(IN:=myString, L:=LEN(myString) - myPos - LEN(S:=myToken) + 1);

  (* Erste Zahl ausschneiden / String *)
  myPos := FIND(IN1:=myString, IN2:=myToken);
  myTeil_2 := LEFT(IN:=myString, L:=myPos - 1);  

  (* Rest des Strings Abschneiden *)
  myTeil_3 := RIGHT(IN:=myString, L:=LEN(myString) - myPos - LEN(S:=myToken) + 1);  
  T3_string := myTeil_3;
  
  (* Erste Zahl *)
  (* Teil vor dem Dezimalpunkt Kopieren und in INT wandeln *)
  myPos := FIND(IN1:=myTeil_1, IN2:='.');
  myString := LEFT(IN:=myTeil_1, L:=myPos - 1);  
  myINT_1 := STRNG_I(myString);
  (* Teil nach dem Dezimalpunkt Kopieren und in INT wandeln *)
  myString := RIGHT(IN:=myTeil_1, L:= LEN(myTeil_1) - myPos);  
  myINT_2 := STRNG_I(myString);
  (* Aus den zwei INT teilen einen Real basteln *)
  T1_real := ((INT_TO_REAL(myINT_1) * EXPD(LEN(myString)))  +  INT_TO_REAL(myINT_2)) / EXPD(LEN(myString)) ;

  (* Zweite Zahl *)
  (* Teil vor dem Dezimalpunkt Kopieren und in INT wandeln *)
  myPos := FIND(IN1:=myTeil_2, IN2:='.');
  myString := LEFT(IN:=myTeil_2, L:=myPos - 1);  
  myINT_1 := STRNG_I(myString);
  (* Teil nach dem Dezimalpunkt Kopieren und in INT wandeln *)
  myString := RIGHT(IN:=myTeil_2, L:= LEN(myTeil_2) - myPos);  
  myINT_2 := STRNG_I(myString);
  (* Aus den zwei INT teilen einen Real basteln *)  
  T2_real := ((INT_TO_REAL(myINT_1) * EXPD(LEN(myString)))  +  INT_TO_REAL(myINT_2)) / EXPD(LEN(myString)) ;
END_FUNCTION

Moin,

Ich hätte eine Frage zu dem LEFT.

Ich versuche gerade xml file (SAP IDOC) nach einem XML Tag zu durchsuchen.

Was würde mypos dann ausgeben ist das die Anfangs oder Endposition?

Das was dort zwischen den Tags steht ist dann z.B. "03-04" wie krieg ich jeweils die ersten beiden Zeichen also 03 und 04 getrennt in zwei Variablen?

Wäre euch wirklich dankbar wenn Ihr einem Noob wie mir helfen könntet :-D
 
Moin,

Ich hätte eine Frage zu dem LEFT.

Ich versuche gerade xml file (SAP IDOC) nach einem XML Tag zu durchsuchen.

Was würde mypos dann ausgeben ist das die Anfangs oder Endposition?

Das was dort zwischen den Tags steht ist dann z.B. "03-04" wie krieg ich jeweils die ersten beiden Zeichen also 03 und 04 getrennt in zwei Variablen?

Wäre euch wirklich dankbar wenn Ihr einem Noob wie mir helfen könntet :-D

Deine Frage ist nicht ganz verständlich, da wir deinen XML-code ja nicht kennen.

mypos gibt gar nichts aus, sondern find sucht nach einem bestimmten Zeichen oder einer Zeichenkette und gibt dann mit mypos das erste Auftreten dieser Zeichenkette an. Das findest du, wenn du, wenn du in der Standard-Library unter IEC-Functions die Funktion Find markierst und dann "F1" drückst.

Die Funktion FC 11 liefert die Position der zweiten Zeichenkette (IN2) innerhalb der ersten Zeichenkette (IN1). Die Suche beginnt links; es wird das erste Auftreten der Zeichenkette gemeldet. Ist die zweite Zeichenkette in der ersten nicht vorhanden, wird Null zurückgemeldet. Die Funktion meldet keine Fehler.

PS: und hier noch Left:

Die Funktion FC 20 liefert die ersten L Zeichen einer Zeichenkette. Ist L größer als die aktuelle Länge der STRING*Variable, wird der Eingangswert zurückgeliefert. Bei L = 0 und bei einem Leerstring als Eingangswert wird ein Leerstring zurückgeliefert. Ist L negativ wird ein Leerstring ausgegeben und das BIE*Bit auf "0" gesetzt.
 
Deine Frage ist nicht ganz verständlich, da wir deinen XML-code ja nicht kennen.

mypos gibt gar nichts aus, sondern find sucht nach einem bestimmten Zeichen oder einer Zeichenkette und gibt dann mit mypos das erste Auftreten dieser Zeichenkette an. Das findest du, wenn du, wenn du in der Standard-Library unter IEC-Functions die Funktion Find markierst und dann "F1" drückst.



PS: und hier noch Left:

Das XML file sieht so aus:

<?xml version="1.0" encoding="UTF-8"?><WMTOID01><IDOC BEGIN="1"><EDI_DC40 SEGMENT="1"><TABNAM>EDI_DC40</TABNAM><MANDT>901</MANDT><DOCNUM>0000000000653782</DOCNUM><DOCREL>640</DOCREL><STATUS>30</STATUS><DIRECT>1</DIRECT><OUTMOD>2</OUTMOD><IDOCTYP>WMTOID01</IDOCTYP><MESTYP>WMTORD</MESTYP><STDMES>WMTORD</STDMES><SNDPOR>SAPG73</SNDPOR><SNDPRT>LS</SNDPRT><SNDPRN>G73CLNT901</SNDPRN><RCVPOR>HRL_660</RCVPOR><RCVPRT>LS</RCVPRT><RCVPRN>HTWAA_680</RCVPRN><CREDAT>20110414</CREDAT><CRETIM>150538</CRETIM><SERIAL>20110213184129</SERIAL></EDI_DC40><E1LTORH SEGMENT="1"><LGNUM>680</LGNUM><TANUM>0000000132</TANUM><BWLVS>601</BWLVS><TRART>A</TRART><BETYP>L</BETYP><BENUM>0000000000</BENUM><BNAME>INABAP-06</BNAME><PERNR>00000000</PERNR><SOLWM> 0.000</SOLWM><SOLEX> 0.000</SOLEX><ISTWM> 0.000</ISTWM><STDAT>00000000</STDAT><ENDAT>00000000</ENDAT><STUZT>000000</STUZT><ENUZT>000000</ENUZT><SWABW>0000</SWABW><VBTYP>J</VBTYP><TAPRI>02</TAPRI><E1LTORI SEGMENT="1"><TAPOS>0001</TAPOS><MATNR>MAOAM-6801-COLA</MATNR><WERKS>1000</WERKS><MEINS>ST</MEINS><LETYP>E1</LETYP><WDATU>20080825</WDATU><WENUM>4900033558</WENUM><WEPOS>0005</WEPOS><VLTYP>682</VLTYP><VLBER>001</VLBER><VLPLA>04-04</VLPLA><VSOLM>1.000</VSOLM><NLTYP>683</NLTYP><NLBER>001</NLBER><NLPLA>WA-ZONE</NLPLA><NSOLM>1.000</NSOLM><MAKTX>Kaubonbon MAOAM Cola</MAKTX><QPLOS>000000000000</QPLOS><QPLOA>000000000000</QPLOA><LGORT>6800</LGORT><SOLPO> 0.000</SOLPO><VOLUM> 0.000</VOLUM><VOLEH>CCM</VOLEH><NWIRM> 0.000</NWIRM><VBELN>0080015424</VBELN></E1LTORI><E1LTORI SEGMENT="1"><TAPOS>0002</TAPOS><MATNR>MAOAM-6801-COLA</MATNR><WERKS>1000</WERKS><MEINS>ST</MEINS><LETYP>E1</LETYP><WDATU>20080825</WDATU><WENUM>4900033558</WENUM><WEPOS>0005</WEPOS><VLTYP>682</VLTYP><VLBER>001</VLBER><VLPLA>03-04</VLPLA><VSOLM>1.000</VSOLM><NLTYP>683</NLTYP><NLBER>001</NLBER><NLPLA>WA-ZONE</NLPLA><NSOLM>1.000</NSOLM><MAKTX>Kaubonbon MAOAM Cola</MAKTX><QPLOS>000000000000</QPLOS><QPLOA>000000000000</QPLOA><LGORT>6800</LGORT><SOLPO> 0.000</SOLPO><VOLUM> 0.000</VOLUM><VOLEH>CCM</VOLEH><NWIRM> 0.000</NWIRM><VBELN>0080015424</VBELN></E1LTORI><E1LTORI SEGMENT="1"><TAPOS>0003</TAPOS><MATNR>MAOAM-6801-ORANGE</MATNR><WERKS>1000</WERKS><MEINS>ST</MEINS><LETYP>E1</LETYP><WDATU>20080825</WDATU><WENUM>4900033558</WENUM><WEPOS>0006</WEPOS><VLTYP>682</VLTYP><VLBER>001</VLBER><VLPLA>05-01</VLPLA><VSOLM>1.000</VSOLM><NLTYP>683</NLTYP><NLBER>001</NLBER><NLPLA>WA-ZONE</NLPLA><NSOLM>1.000</NSOLM><MAKTX>Kaubonbon MAOAM Orange</MAKTX><QPLOS>000000000000</QPLOS><QPLOA>000000000000</QPLOA><LGORT>6800</LGORT><SOLPO> 0.000</SOLPO><VOLUM> 0.000</VOLUM><VOLEH>CCM</VOLEH><NWIRM> 0.000</NWIRM><VBELN>0080015424</VBELN></E1LTORI></E1LTORH></IDOC></WMTOID01>

Ist ein typischer Sap Transportauftrag, aus dem ich die Lagerplatznummern raussuchen möchte.

Der Lagerplatz steht zwischen <VLPLA> und </VLPLA>

Wäre also in diesem Beispiel: <VLPLA>05-01</VLPLA>
 
Zuviel Werbung?
-> Hier kostenlos registrieren
OK ...
dann würde ich es so machen :
- mit FIND nach <VLPLA> suchen und Position merken
- mit FIND nach </VLPLA> suchen und Position merken
- den zwischen den gemerkten Positionen liegenden String mit MID ausschneiden.
- in dem ausgeschnittenen String mit FIND nach '-' suchen und nun wieder mit MID in die beiden Teile zerlegen.

Gruß
Larry
 
Wäre also in diesem Beispiel: <VLPLA>05-01</VLPLA>

Dann würde ich nach <VLPLA> suchen dir würde dann in mypos das erste Auftreten von <VLPLA> und da das erste Zeichen ausgegeben.
Dann kannst du noch nach </VLPLA> suchen, auch hier bekommst du die Position des ersten Zeichens ausgegeben.

Mit diesen Angaben kannst du gezielt 05 und 01 ausschneiden, im Prinzip benötigst du die Suche nach </VLPLA> nicht einmal, das wäre nur zur Sicherheit und Kontrolle, ob die Daten die korrekte Länge haben.

05: ist das 8.+9. Zeichen + mypos
01: ist das 11.+12. Zeichen + mypos

du könntest also mit der Funktion mid

pos --> (mypos + 8 ) Länge --> 2 Zeichen auschneiden
pos --> (mypos + 11 ) Länge --> 2 Zeichen ausschneiden
 
Erst mal Danke für die Tipps, das hat mir enorm geholfen. Eine Frage hab ich noch:

In dem Idoc stehen mehrere Lagerplätze, kann ich um die anderen (also alle nach dem ersten) zu finden einfach nochmal einen Find machen oder muss ich dazu den ersten Treffer löschen?

Mfg Alex
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Erst mal Danke für die Tipps, das hat mir enorm geholfen. Eine Frage hab ich noch:

In dem Idoc stehen mehrere Lagerplätze, kann ich um die anderen (also alle nach dem ersten) zu finden einfach nochmal einen Find machen oder muss ich dazu den ersten Treffer löschen?

Mfg Alex

Du mußt die ersten dazu löschen. Ich hab das immer per Delete gemacht, etwas so:


Code:
Pos :=                  FIND(IN1 := Auftrag, IN2 := SuchString);
Car_id_No :=            MID(IN := Auftrag ,L := Pos-1 ,P := 1);
Auftrag :=          DELETE(IN := Auftrag, L := Pos + Length, P := 1);

Pos :=                  FIND(IN1 := Auftrag, IN2 := SuchString);
Kind_of_production :=   MID(IN := Auftrag ,L := Pos-1 ,P := 1);
Auftrag :=          DELETE(IN := Auftrag, L := Pos + Length, P := 1);

Pos :=                  FIND(IN1 := Auftrag, IN2 := SuchString);
IO_Flag :=              MID(IN := Auftrag ,L := Pos-1 ,P := 1);
Auftrag :=          DELETE(IN := Auftrag, L := Pos + Length, P := 1);
 
FIND sucht immer nur bis zur ersten Übereinstimmung. Du müßtest also dann bis Ende </VLPLA> den String löschen und dann wieder suchen. Der Befehl dafür wäre dann DELETE.
Beachte aber bitte :
Der String kann nicht unbegrenzt lang sein ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Und wie krieg ich die dann am besten in einen DB?

ich hab jetzt einen Aufgemacht mit 2 Arrays
einmal die Spalte für die ersten beiden Zahlen
und einmal die Zeile für die letzten beiden
 
Heh Ralle - das klappt heute aber wieder mit uns ... :D:D:D

Yep, geht wie Butter! :ROFLMAO:

@Aslof
Oh oh, dein XML ist 2663 Zeichen lang, wenn ich das richtig sehe.
S7-Strings sind max. 255 Zeichen lang, also mußt du das ankommende Paket sinnvoll zerlegen, um mit den Stringfunktionen zu arbeiten.

Es gibt noch eine Alternative, die habe ich mal irgendwann genutzt.
Die Daten kommen ja sicher per Ethernet oder so in einem DB bei dir an. Dort liegt dann ein Array of Byte o.ä.

Nun könnte man diese Array nach dem ersten Vorkomen von "<" durchsuchen, hat man das, schaut man, ob das zweite Zeichen "V" ist, wenn ja, das dritte Zeichen und so weiter, wenn nein, dann wieder nach "<" suchen. Das ist kein so großes Problem in SCL. So findest du ebenfalls deine Werte und kannst dann die betreffenden Byte ausschneiden.
 
Zurück
Oben