Skip to main content

Exemples

Le Generic String Base une bibliothèque est fournie pour rendre le traitement des chaînes aussi simple que possible. Cependant, il utilise VAR_GENERIC CONSTANT fonction de compilation et ne peut donc être utilisée qu'à partir de CODESYS Mise à jour 5 V3.5 SP19.

Bibliothèque : Generic String Base

Voici un exemple (myString) d'un GSB.UTF8String d'une capacité de 128 octets est créé et le segment de chaîne avec la valeur d'une variable STRING (chiffre romain 1968) est initialisé. Les méthodes de STR.IString sont disponibles.

Exemple 9. À partir de STRING à IString
VAR
    myString : GSB.UTF8String<128> := (sValue := UTF8#'𝕄CMℒ✖Ⅷ'); // römisch 1968    
    psString : POINTER TO STRING;    udiSize, udiLength : UDINT;    xASCII, xOk : BOOL;
END_VAR
 
    psString := myString.GetSegment(udiSize=>udiSize, udiLength=>udiLength, xASCII=>xASCII); // Conversion back to the STRING data type
 
xOk := (
    myString.IsValid() AND // A valid UTF-8 encoding is present
    udiSize = 128 AND // The capacity of the string in bytes
    myString.Len() = 17 AND // The current length of the string in bytes
    STR.RuneCount(myString) = 6 // The current number of characters in the string
);


Exemple 10. Fonction du générateur de chaînes
VAR
    myString : GSB.UTF8String<20> := (sValue := UTF8#'𝕄CMℒ✖Ⅷ'); // roman 1968
    sValue : STRING := 'wurden in Mexico-Stadt die';
    wsValue : WSTRING := "ⅩⅨ.";
    diSpace : STR.RUNE := 32;
    myValue : GSB.UTF8String<128> := (sValue := UTF8#'Ѻℓƴμρ☤ṧḉнεη $$ρї℮łℯ α♭ℊεℌαʟ⊥℮ᾔ.');
 
    myBuilder : GSB.Builder<(*udiInitialCapacity*) 64, (*usiExtensionFactor*) 50> := (itfString:=myString);
    myResult : GSB.UTF8String<128>;
 
    {attribute 'monitoring_encoding' := 'UTF-8'}
    sResult : STRING(128) := UTF8#'𝕄CMℒ✖Ⅷ wurden in Mexico-Stadt die ⅩⅨ. Ѻℓƴμρ☤ṧḉнεη $$ρї℮łℯ α♭ℊεℌαʟ⊥℮ᾔ.';
 
    psResult : POINTER TO STRING;
    udiLength : UDINT;
    xOk : BOOL;
END_VAR
 
myBuilder.WriteRune(diSpace);
myBuilder.WriteString(sValue);
myBuilder.WriteRune(diSpace);
myBuilder.WriteWString(wsValue);
myBuilder.WriteRune(diSpace);
myBuilder.WriteIString(myValue);
 
udiLength := myBuilder.Len(); // The number of bytes occupied in the builder.
myBuilder.ToIString(myResult); // The individual parts of the string are copied together to myResult.
 
psResult := myResult.GetSegment(); 
xOk := (psResult^ = sResult); // Both memory areas should have the same content.


Dans l'exemple ci-dessus, une instance du générateur est créée avec une capacité initiale de 64 octets (udiInitialCapacity) et un facteur dynamique de 50 (usiExtensionFactor). La chaîne générée plus haut est toujours transmise dans la déclaration et, par conséquent, le générateur est rempli avec cette chaîne (UTF8#'𝕄CMℒ✖Ⅷ'). À l'aide du usiExtensionFactor paramètre, augmente le générateur de 50 % lorsque sa capacité actuelle est épuisée.

Exemple 11. Lire un fichier à l'aide du générateur
VAR
    sPath : STRING := 'myFilePath';
    hFile : RTS_IEC_HANDLE := RTS_INVALID_HANDLE;
    myBuilder : GSB.Builder<(*udiInitialCapacity*) 16#10000, (*usiExtensionFactor*) 50>;
    abyBuffer : ARRAY[0..4095] OF BYTE;
    pbyData : POINTER TO BYTE;
    udiSize : UDINT;
    udiCount : UDINT;
    eEncoding : SCV.ENCODING;
    eErrorID : SCV.ERROR;
    udiResult : RTS_IEC_RESULT;
END_VAR
 
hFile := SysFileOpen(sPath, ACCESS_MODE.AM_READ, ADR(udiResult));
IF udiResult <> ERRORS.ERR_OK THEN
    // handle error condition
    RETURN;   
END_IF
 
REPEAT // fake loop - We need the EXIT feature
    pbyData := ADR(abyBuffer);
    udiSize := TO_UDINT(SysFileRead(hFile, pbyData, XSIZEOF(abyBuffer), ADR(udiResult)));
    IF udiResult <> ERRORS.ERR_OK THEN
        // handle error condition
        EXIT;   
    END_IF
 
    // Determination of the file encoding
    udiCount := SCV.DecodeBOM(pbyData, udiSize, eEncoding=>eEncoding, eErrorID=>eErrorID);
    IF eErrorID <> 0 THEN
        // handle error condition
        EXIT;
    END_IF
 
    pbyData := pbyData + udiCount;
    udiSize := udiSize - udiCount;
 
    WHILE udiSize > 0 DO
        // Convert file content to UTF-8 and copy to Builder-Content
        udiCount := myBuilder.WriteMemSegment(pbyData, udiSize, eEncoding, eErrorID=>eErrorID);
        IF eErrorID <> 0 THEN
            // handle error condition
            EXIT;
        END_IF
        pbyData := ADR(abyBuffer);
        udiSize := TO_UDINT(SysFileRead(hFile, pbyData, XSIZEOF(abyBuffer), ADR(udiResult)));
        IF udiResult <> ERRORS.ERR_OK THEN
            // handle error condition
            EXIT;   
        END_IF
    END_WHILE
UNTIL TRUE
END_REPEAT
 
IF hFile <> RTS_INVALID_HANDLE THEN
    SysFileClose(hFile);
    hFile := RTS_INVALID_HANDLE;
    udiCount : UDINT;
END_IF


Exemple 12. Analyse du contenu d'une instance de générateur
VAR
    myRange : SBD.Range := (itfBuilder := myBuilder);
    diRune : STR.RUNE;
    eError : STR.ERROR;
END_VAR
 
myRange.Reset();
WHILE (diRune := myRange.GetNextRune(eErrorID=>eErrorID)) <> 0 AND_THEN eErrorID = 0 DO
    IF UC.IsSpace(diRune) THEN
        // The characters in the builder which are considered as spaces according to UNICODE are counted.
        udiCount := udiCount + 1;
    END_IF
END_WHILE


Pour transmettre du contenu codé en UTF-8, aucun cache n'est nécessaire pour le codage de la conversion car les données sont déjà codées en UTF-8 dans le générateur. Par conséquent, le contenu d'un segment d'un générateur peut être envoyé directement, par exemple via une connexion TCP/IP

Exemple 13. Transport du contenu codé en UTF-8 d'un générateur sur le réseau
VAR
    itfConnection : NBS.IConnection;
    pbySegment : POINTER TO BYTE;
    udiSize : UDINT;
    eError : NBS.ERROR;
END_VAR
 
(* Provide an active itfConnection *)
 
pbySegment:= myBuilder.GetFirstSegment(udiSize=>udiSize, eErrorID=>eErrorID);
WHILE pbySegment <> 0 AND eErrorID = 0 DO
    eError := itfConnection.Write(pbySegment, udiSize, udiCount=>udiCount);
    IF eError <> 0 OR udiCount <> udiSize THEN
        // Handle Error
        EXIT;
    END_IF
    pbySegment := myBuilder.GetNextSegment(pbySegment, udiSize=>udiSize, eErrorID=>eErrorID);
END_WHILE
 
(* e.g. Close itfConnection *)


En collaboration avec StringPool et RangePool blocs fonctionnels

Le code suivant montre comment utiliser la dynamique IString instances provenant d'un StringPool. StringPool ou un RangePool est bien adapté pour être transmis aux parties subordonnées d'un programme. Ils peuvent ensuite créer les instances correspondantes à partir du pool correspondant selon les besoins, les utiliser, puis renvoyer ces instances dans le pool.

Exemple 14. Travailler avec StringPool et RangePool
VAR
    myString : GSB.UTF8String<256> := (sValue:=UTF8#'Was du nicht willst, dass man dir tu’, das füg auch keinem andern zu.');
    myRange : STR.Range := (itfString:=myString);
 
    myStringPool : GSB.StringPool<(*udiStringSize*) 30, (*udiInitialCapacity*) 25, (*usiExtensionFactor*) 0>;
    myRangePool : GSB.RangePool<GSB.RANGE_TYPE.ISTRING, (*udiInitialCapacity*) 10, (*usiExtensionFactor*) 0>;
 
    diRune : STR.RUNE;
    eErrorID : STR.ERROR;
    itfSubString : STR.IString;
    liStart, liEnd : LINT;
    udiCount : UDINT;
END_VAR
 
myRange.Reset();
// Decompose myString into substrings and analyze them via a subroutine.
WHILE (diRune:=myRange.GetNextRune(eErrorID=>eErrorID)) <> 0 AND eErrorID = 0 DO
    IF diRune = 16#2C (*,*) OR diRune = 16#2E (*.*) THEN
        itfSubString := myStringPool.GetString();
        IF  itfSubString = 0 THEN
            (* Handle Error *)
            EXIT;
        END_IF
        myString.ToIString(itfSubString, liStart+1, liEnd, eErrorID=>eErrorID);
        IF eErrorID <> 0 THEN
            (* Handle Error *)
            EXIT;
        END_IF
        // Analyse the substring and use pool's
        // Will release  itfSubString
        udiCount := Analyse(itfSubString, myStringPool, myRangePool);
        (* ... Handle Result ... *)
        IF diRune = 16#2E (*.*) THEN
            EXIT;
        END_IF
        diRune:=myRange.GetNextRune(eErrorID=>eErrorID);
        IF diRune = 16#20 (* space *) AND eErrorID = 0 THEN
            liEnd := liEnd + 1;
        ELSE
            myRange.UngetLastRune();
        END_IF
        liStart := liEnd + 1;
    END_IF
    liEnd := liEnd + 1;
END_WHILE


Utilisation des catégories de caractères Unicode

La norme Unicode vise à capturer numériquement tous les caractères du monde entier et à décrire leurs propriétés. Pour ce faire, les personnages sont regroupés en groupes (catégories). Dans la bibliothèque Unicode, il existe des fonctions qui vérifient la catégorie d'un caractère. Ces fonctions renvoient TRUE si le caractère transmis appartient à la catégorie correspondante ; sinon FALSE est renvoyé.

Nom

Fonction

IsControl

Reconnaît les caractères de contrôle généraux

IsLetter

Reconnaît les lettres au sens large

IsMark

Reconnaît les combinaisons de caractères, par exemple les caractères diacritiques

IsDigit

Reconnaît les chiffres décimaux

IsLower

Reconnaît les lettres minuscules

IsNumber

Reconnaît les chiffres et les caractères qui s'appliquent aux nombres

IsGraphic

Reconnaît uniquement les caractères imprimables (y compris les différents types d'espaces)

IsUpper

Reconnaît les lettres majuscules

IsPunct

Reconnaît les caractères de ponctuation

IsPrint

Reconnaît uniquement les caractères imprimables (ne prend en compte que 16#20 (comme caractère d'espace)

IsTitle

Reconnaît les lettres majuscules pour les en-têtes

IsSpace

Détecte les espaces de différentes largeurs, les sauts de ligne, etc.

IsSymbol

Reconnaît les symboles dans un sens plus large, par exemple les symboles mathématiques et les symboles monétaires.

Le contenu d'un IString ou IBuilder l'instance peut être analysée « caractère par caractère » à l'aide d'un bloc fonctionnel approprié de type Range. Les fonctions de la bibliothèque Unicode peuvent être très utiles pour l'analyse

Exemple 15. Analyse des personnages
VAR
    myString : GSB.UTF8String<50> := (sValue:='Hello World!');
    myBuilder : GSB.Builder<100, 0> := (itfString:=myString);
    mySRange : STR.Range := (itfString:=myString);
    myBRange : SBD.Range := (itfBuilder:=myBuilder);
    diSRune, diBRune : STR.RUNE;
    eErrorID : STR.ERROR;
    udiCount : UDINT;
END_VAR
 
WHILE (diSRune:=mySRange.GetNextRune(eErrorID=>eErrorID)) <> 0 AND eErrorID = 0 DO
    diBRune := myBRange.GetNextRune();
    IF diSRune <> diBRune THEN
        (* Solle nicht vorkommen *)
    END_IF
    IF UC.IsSpace(diSrune) THEN
        udiCount := udiCount + 1;
    END_IF
END_WHILE


Conversion de caractères

  • Convertir les lettres en majuscules (UC.ToUpper)

  • Convertissez les lettres en minuscules (UC.ToLower)

Exemple 16. Conversion
VAR
    diRuneA, diRuneB : STR.RUNE;
END_VAR
 
diRuneA := 16#1F3; // U+01F3 = Dž
diRuneB := UC.ToUpper(diRuneA); // U+01F1 = DZ
diRuneA := UC.ToLower(diRuneB); // U+01F3 = Dž
diRuneB := UC.ToTitle(diRuneA); // U+01F2 = Dz


Comparaison de chaînes

  • Sensibilisation aux majusculesSTR.Compare)

  • Pas de distinction majuscules/minuscules (UC.EqualFold)

Exemple 17. Comparaison de chaînes
VAR
     myFirstString : GSB.UTF8String<50> := (sValue:='test');
     mySecondString : GSB.UTF8String<50> := (sValue:='Test');
      
     myThirdString  : GSB.UTF8String<50> := (sValue:='CoDeSys');
     myFourthString : GSB.UTF8String<50> := (sValue:='CODESYS');
      
     diResult : DINT;
     xEqual : BOOL;
END_VAR
 
/// Comparing two Strings lexicographically
/// diResult = 1 --> myFirstString > mySecondString
diResult := STR.Compare(myFirstString, mySecondString);
 
/// Unicode defined simple case folding
/// xEqual = TRUE --> myThirdString == myFourthString
xEqual := UC.EqualFold(
    ADR(myThirdString.sValue), myThirdString.Len(),
    ADR(myFourthString.sValue), myFourthString.Len()
);