Step 7 String aus Liste suchen

plc2023

Level-1
Beiträge
12
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich habe folgendes Fragestellung:

CPU 315-2 PN/DP
S7 Classic v5.6 SP2

Ich habe eine Materialnummer mit anschließender Zufallszeichenfolge als String (String A) und möchte diese gegen eine Liste aus Materialnummern vergleichen (String B). Habe ich den passenden String B gefunden muss zu diesem der passende Auftrag (String C) zugeordnet werden.

Im kleinen habe ich das schonmal mit den FC FIND und anschließenden Auswertung der Returns für Vergleich String A und B.
Mit den Returns habe ich dann jeweils weitergearbeitet und den String C aus meinem DB geladen ( -> ich weiß welcher String C zu String B gehört).

Funktioniert im kleinen, aber ist aufwendig.
Ich möchte das aber etwas schlanker und universeller haben.

Geht das auf meiner CPU per SCL o.ä. nicht schneller / flexibler?

Im Anlegen der DBs bin ich frei, das kann ich mir im Endeffekt schreiben wie ich möchte.

Als Info für die Längen:

String A hat 98 Zeichen + 2 Byte Header
String B hat 13 Zeichen + 2 Byte Header
String C hat 20 Zeichen + 2 Byte Header

Anzahl der String B + C wird sich im Bereich 20 - 50 bewegen


Danke schonmal für eure Hilfe!
 
... ( -> ich weiß welcher String C zu String B gehört). ...
Ich weiss es aber leider nicht und verstehe vermutlich genau darum nicht, worauf Du hinaus willst.
Wenn Du ein Array Of String namens B und ein Array Of String namens C hast und die Indizes der zusammengehörenden Strings identisch sind (z.B. B[123] ist C[123] zugeordnet).
Meinst Du so etwas?
Funktioniert im kleinen, aber ist aufwendig.
?
Im kleinen habe ich das schonmal mit den FC FIND und anschließenden Auswertung der Returns für Vergleich String A und B.
Was Du hiermit sagen willst, ist mir auch nicht so ganz klar.
Mit FC Find kannst Du feststellen, ob ein String in einem anderen String enthalten ist.
Ist es denn das, was Du damit machen willst?
Geht das auf meiner CPU per SCL o.ä. nicht schneller / flexibler?
Schneller bzw. flexibler als was? Verglichen womit?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Okay ich versuche es nochmal etwas besser zu beschreiben:

String A ist immer Unterschiedlich, allerdings sind die ersten 13 Zeichen (Materialnummer) identisch zu einer Materialnummer aus einer Liste von verschiedenen Strings ( Array of String beinhaltet String B)

Der Indizes vom Array String B ist dann 1:1 dem Indizes vom Array of Strings C.

Im kleinen meinte ich, ich habe das für 4 verschiedene String B in FUP so programmiert:

Code:
Netzwerk 1 - STRING Suche

IN1 = String A und IN2 = String B[1] mit FIND verglichen  -> RET_VAL = Ergebnis AB1
IN1 = String A und IN2 = String B[2] mit FIND verglichen  -> RET_VAL = Ergebnis AB2
IN1 = String A und IN2 = String B[3] mit FIND verglichen  -> RET_VAL = Ergebnis AB3
IN1 = String A und IN2 = String B[4] mit FIND verglichen  -> RET_VAL = Ergebnis AB4

Netzwerk 2 - Abfrage Ergebnis

Ergebnis AB1 == 1 ODER Ergebnis AB2 == 1 ODER Ergebnis AB3 == 1 ODER Ergebnis AB4 == 1   -> Gefunden == TRUE

Netzwerk 3 - StringC auf Zielstring kopieren

Gefunden UND ( Ergebnis AB1 == 1 ) -> BLKMOVE StringC[1] auf STRING D
Gefunden UND ( Ergebnis AB1 == 2 ) -> BLKMOVE StringC[2] auf STRING D
Gefunden UND ( Ergebnis AB1 == 3 ) -> BLKMOVE StringC[3] auf STRING D
Gefunden UND ( Ergebnis AB1 == 4 ) -> BLKMOVE StringC[4] auf STRING D


Für die kleine Anzahl an Vergleichen geht das ja, nur bei einer größeren Anzahl wird das halt aufwändiger und ich hinterfrage ob es nicht einfacher möglich ist. Ich hoffe es ist nun verständlicher worauf ich hinaus möchte.
 
...
Im kleinen meinte ich, ich habe das für 4 verschiedene String B in FUP so programmiert:

Code:
Netzwerk 1 - STRING Suche

IN1 = String A und IN2 = String B[1] mit FIND verglichen  -> RET_VAL = Ergebnis AB1
...
IN1 = String A und IN2 = String B[4] mit FIND verglichen  -> RET_VAL = Ergebnis AB4

Netzwerk 2 - Abfrage Ergebnis

Ergebnis AB1 == 1 ODER Ergebnis AB2 == 1 ODER Ergebnis AB3 == 1 ODER Ergebnis AB4 == 1   -> Gefunden == TRUE

Netzwerk 3 - StringC auf Zielstring kopieren

Gefunden UND ( Ergebnis AB1 == 1 ) -> BLKMOVE StringC[1] auf STRING D
...
Gefunden UND ( Ergebnis AB1 == 4 ) -> BLKMOVE StringC[4] auf STRING D

Für die kleine Anzahl an Vergleichen geht das ja, nur bei einer größeren Anzahl wird das halt aufwändiger ...
Ich schlage eine in SCL programmierte ProgrammSchleife vor. Deine Art, in FUP zu programmieren, erinnert mich ohnhin schon mehr an SCL als an FUP. ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So nachdem ich bisher noch etwas in SCL programmiert habe, habe ich mich mal rangewagt und versucht meine Funktion nachzubilden:

Compiler bringt mir erstmal keine Fehler. Würde das so funktionieren?

Den String A müsste ich dann bevor ich ihn an den FC übergebe auf die Länge 13 (was ja für mich relevant ist) kürzen.

Code:
FUNCTION FC7500 : INT


VAR_INPUT
    stringA: STRING[13];
    freigabe: BOOL;
    typ: INT;
    anzahl_stringBC: INT;
END_VAR

VAR_OUTPUT
    ergebnis : BOOL;
    diff: INT;
    stringD: STRING[20];
END_VAR

VAR_TEMP
    ergebnis_tmp : BOOL;
    iStringB : INT;
    iStringC : INT;
    erg : INT;   
END_VAR

db7500.tmpStringA:= stringA;      // String A zwischenspeichern

IF freigabe = true THEN
// Freigabe vorhanden


    FOR iStringB := 0 TO anzahl_stringBC BY 1 DO
    // Stringvergleich String A mit StringB 1...XX im Array
        "S7 STR_COMP"   (STRING_1 := db7500.tmpStringA                 // String A
                        ,STRING_2 := db7500.tmpStringB[iStringB]       // StringB[i] 
                        ,EQUAL := ergebnis_tmp                         // OUT: BOOL
                        ,DIFF := diff                                  // OUT: INT
                        );                                             // VOID
        
    IF ergebnis_tmp = true THEN
        // Schleife beenden wenn String gefunden
        iStringB:= iStringC;
        EXIT;
        ;
     END_IF;
              
    END_FOR;

erg:= SFC20(srcblk:= db7500.tmpStringC[iStringC] , dstblk:= stringD);

ELSE
// Keine Freigabe -> leer String laden   
erg:= SFC20(srcblk:= db7500.leer_string , dstblk:= stringD);
;

END_IF;
;

FC7500 := 100;
END_FUNCTION

Der DB sieht wie folgt aus:

Unbenannt.JPG
Danke euch!
 
Ich hätte dazu ein paar Fragen / Anmerkungen :
- wenn ich das eingangs richtig verstanden habe ist der Suchstring nmicht am Anfang des DB-Strings sondern ggf. mitten drin ?
falls ja dann wäre FIND hier der richtigere Ansatz.
- Ein String-Vergleich schaut auf 100%ig identisch - einen 13 Zeichen langen String kannst du nicht mit einem 20 Zeichen langen String vergleichen.
wie groß ist der Übergabe-String ?
- wenn du deinen Übergabe-String abschneiden willst so wäre hierfür LEFT der Ansatz
- du willst oben doch sicherlich den Index speichern - dann müsste es "iStringC := iStringB;" heissen
- bei SCL kannst du Strings direkt zuweisen und brauchst nicht den SFC20 - es kann also so heissen : "stringD := db7500.leer_string"

Den Rest müsste dann der Test ergeben ...
 
wenn ich das eingangs richtig verstanden habe ist der Suchstring nmicht am Anfang des DB-Strings sondern ggf. mitten drin ?
Ne der wäre schon am Anfang. Sprich die ersten 13 Zeichen des Strings wären auch die zu vergleichenden.

Ein String-Vergleich schaut auf 100%ig identisch - einen 13 Zeichen langen String kannst du nicht mit einem 20 Zeichen langen String vergleichen.
wie groß ist der Übergabe-String ?
Ich würde den String zur Übergabe auf 13 Zeichen reduzieren damit ich ihn 1:1 vergleichen kann

du willst oben doch sicherlich den Index speichern - dann müsste es "iStringC := iStringB;" heissen
Ja, danke!
bei SCL kannst du Strings direkt zuweisen und brauchst nicht den SFC20 - es kann also so heissen : "stringD := db7500.leer_string"
Erledigt.

Ich habe mein Program jetzt noch etwas angepasst und die Variablen auf Outputs gelegt, lässt sich zum Test besser beobachten.
Ich habe die Vergleichstrings auch gleich belegt um die Funktion einfach mal zu testen.

Leider habe ich nun das Problem dass sobald ich die Freigabe gebe, der Schleifenzähler auf die max Anzahl hochläuft und dann stehen bleibt.
Er müsste doch bei gleichem String in die IF Schleife springen. Wieso tut er das nicht?

Anbei der Code und Screenshots vom Zustand.

Code:
FUNCTION FC7500 : INT

VAR_INPUT
    stringA: STRING[13];
    freigabe: BOOL;
    anzahl_stringBC: INT;
END_VAR

VAR_OUTPUT
    ergebnis : BOOL;
    diff: INT;
    stringD: STRING[20];
    iStringB : INT;
    iStringC : INT;
    ergebnis_tmp : BOOL;
END_VAR

db7700.tmpStringA:= stringA;      // String A zwischenspeichern

IF freigabe = true THEN
// Freigabe vorhanden

    FOR iStringB := 0 TO anzahl_stringBC BY 1 DO
    // Stringvergleich String A mit StringB 1...XX im Array 
    
        "S7 STR_COMP"   (STRING_1 := db7700.tmpStringA                 // String A
                        ,STRING_2 := db7700.tmpStringA                     //db7700.tmpStringB[iStringB]       // String B[i] 
                        ,EQUAL := ergebnis_tmp                         // OUT: BOOL
                        ,DIFF := diff                                  // OUT: INT   
                        );                                             

    IF ergebnis_tmp = true THEN
        // Schleife beenden wenn String gefunden
        iStringC:= iStringB;
        stringD:= db7700.tmpStringC[iStringC];
        ergebnis:= true;
        EXIT;
        
     END_IF;
    
              
    END_FOR;


ELSE
// Keine Freigabe -> leer String laden   
stringD:= db7700.leer_string;
iStringB := 0;
iStringC := 0;
;

END_IF;
;

FC7500 := 100;
END_FUNCTION

Unbenannt.JPGUnbenannt1.JPG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mir ist hier gerade nur aufgefallen, dass du Zeichen zu Vergleichen versuchst und keine Strings. Das könnte schon der Grund sein (für den Compare-FC). Wenn du es erst mit Zeichen testen willst dann kannst du die direkt vergleichen - also "if String_1 = String_2 then ..."
 
Danke für den Tipp. Ich dachte eigentlich der Compare FC macht das gleiche wie in FUP und vergleicht die Strings.

Wenn ich es als IF Bedingung vergleiche funktioniert es. Einzig war noch wichtig die Laufvariable der FOR Schleife von 0 auf 1 am Start zu ändern. Jetzt funktioniert es wie gewünscht im Test. Ich werde es nun im Laufe der Woche mal in der Realumgebung testen.

Anbei der Code falls jemand dasselbe Problem hat:

Code:
FUNCTION FC7500 : INT

VAR_INPUT
    stringA: STRING[13];
    freigabe: BOOL;
    anzahl_stringBC: INT;
END_VAR

VAR_OUTPUT
    ergebnis : BOOL;
    stringD: STRING[20];
    iStringB : INT;
    iStringC : INT;
END_VAR

db7700.tmpStringA:= stringA;      // String A zwischenspeichern

IF freigabe = true THEN
// Freigabe vorhanden

    FOR iStringB := 1 TO anzahl_stringBC BY 1 DO   
    // Stringvergleich String A mit StringB 1...XX im Array 
    
    IF db7700.tmpStringA = db7700.tmpStringB[iStringB] THEN
        // Schleife beenden wenn String gefunden
        iStringC:= iStringB;
        stringD:= db7700.tmpStringC[iStringC];
        ergebnis:= true;
        EXIT;     
     END_IF;
    
              
    END_FOR;

ELSE
// Keine Freigabe -> leer String laden   
stringD:= db7700.leer_string;
iStringB := 0;
iStringC := 0;
;
END_IF;
;
FC7500 := 100;
END_FUNCTION
 
Zurück
Oben