1

I am attempting to compare one character of a string to see if it is my delimiter character. However, when I execute the following code the value that gets placed in the variable valstring is a number that represents the byte that was converted to a string and not a character itself. For Example the value may be the string '58'.

Through my testing in CoDeSys using the debugging features I know that the string sReadLine contains a valid string of characters. I'm just not sure of the syntax to single only one of them out; the sReadLine[valPos + i] part is what I don't understand.

sReadLine : STRING;
valstring : STRING;
i         : INT;
valPos    : INT;

FOR i := 0 TO 20 DO
    IF BYTE_TO_STRING(sReadLine[valPos + i]) = '"' THEN
        EXIT;
    END_IF
    valstring := CONCAT(STR1 := valstring, STR2 := BYTE_TO_STRING(sReadLine[valPos + i]));
END_FOR
Michael LeVan
  • 528
  • 2
  • 8
  • 21
  • Can you explain what you want to achieve? You want to separate line by a delimiter to create an array or what? Maybe there is completely different solution to your task than simply answer to problem question. Something tells me that the thing you want to do, have to be solved completely differently. โ€“ Sergey Romanov Nov 08 '19 at 14:02

3 Answers3

1

I think you have multiple choises.

1) Use built-in string functions instead. You can use MID function get get part of a string. So in your case something like "get one character from valPos + 1 from sReadLine.

FOR i := 0 TO 20 DO
    IF MID(sReadLine, 1, valPos + i) = '"' THEN
        EXIT;
    END_IF
    valstring := CONCAT(STR1 := valstring, STR2 := MID(sReadLine, 1, valPos + i));
END_FOR

2) Convert the ASCII byte to string. In TwinCAT systems, there is a function F_ToCHR. It takes a ASCII byte in and returns the character as string. I can't find something like that for Codesys, but i'm sure there would be a solution in some library. So please note that this won't work in Codesys without modifications:

FOR i := 0 TO 20 DO
    IF F_ToCHR(sReadLine[valPos + i]) = '"' THEN
        EXIT;
    END_IF
    valstring := CONCAT(STR1 := valstring, STR2 := F_ToCHR(sReadLine[valPos + i]));
END_FOR

3) The OSCAT library seems to have a CHR_TO_STRING function. You could use this instead of F_ToCHR in step 2.

4) You can use pointers to copy the ASCII byte to a string array (MemCpy) and add a string end character. This needs some knowledge of pointers etc. See Codesys forum for some example.

5) You can write a helper function similar to step 2 youself. Check the example from Codesys forums. That example doesn't include all characters so it needs to be updated. It's not quite elegant.

Quirzo
  • 1,183
  • 8
  • 10
1

When you convert a byte to a string, what is beeing converted is the digital representation of the byte. This means you are interpreting that byte as an ascii character (The ascii decimal value of : is 58).

So if you want to Concat chars instead of their ascii decimal representation, you need another function:

valstring := CONCAT(STR1 := valstring, STR2 := F_ToCHR(sReadLine[valPos + i]));

EDIT:

As Quirzo, I couldn't find a similar F_ToCHR function for Codesys, but you could easily build one yourself. For example:

Declaration Part:

FUNCTION F_ASCII_TO_STRING : STRING
VAR_INPUT
    input : BYTE;
END_VAR
VAR
    ascii   : ARRAY[0..255] OF STRING(1):= 
    [
        33(' '),'!','"','#',
        '$$' ,'%' ,'&' ,'ยด',
        '(' ,')' ,'*' ,'+' ,
        ',' ,'-' ,'.' ,'/' ,
        '0' ,'1' ,'2' ,'3' ,
        '4' ,'5' ,'6' ,'7' ,
        '8' ,'9' ,':' ,';' ,
        '<' ,'=' ,'>' ,'?' , 
        '@' ,'A' ,'B' ,'C' ,
        'D' ,'E' ,'F' ,'G' ,
        'H' ,'I' ,'J' ,'K' ,
        'L' ,'M' ,'N' ,'O' ,
        'P' ,'Q' ,'R' ,'S' ,
        'T' ,'U' ,'V' ,'W' ,
        'X' ,'Y' ,'Z' ,'[' ,
        '\' ,']' ,'^' ,'_' ,
        '`' ,'a' ,'b' ,'c' ,
        'd' ,'e' ,'f' ,'g' ,
        'h' ,'i' ,'j' ,'k' ,
        'l' ,'m' ,'n' ,'o' ,
        'p' ,'q' ,'r' ,'s' ,
        't' ,'u' ,'v' ,'w' ,
        'x' ,'y' ,'z' ,'{' ,
        '|' ,'}' ,'~' 
    ];

END_VAR

Implementation part:

F_ASCII_TO_STRING := ascii[input];
Filippo Boido
  • 1,136
  • 7
  • 11
  • Thank you for the good response. I was able to get to a satisfactory solution by making my own charAt function. However, I used a combination of the LEFT and RIGHT functions as follows: charAt := RIGHT(STR := str, SIZE := LEN(STR := str) - index + 1); charAt := LEFT(STR := charAt, SIZE := 1); I like your answer as it actually converts the byte to ascii. Thank you for your answer but I gave the credit to Quirzo since his option 1 was exactly what I was looking for. โ€“ Michael LeVan Nov 11 '19 at 22:36
1

As Sergey said, this might not be an optimal solution to your problem. It seems like you want to extract the longest substring not containing any character " from initial input sReadLine to valstring, starting from position valPos. In your implementation, for each valid input character, CONCAT() needs to search for the end of valstring, before appending only 1 character to it.

You should rather decompose your problem and use two standard functions to be optimal:

  • FIND() --> to get the position of the next character " (or to know if there is none),
  • MID() --> to create a string from initial position up to before the first character " (or the end of the input string).

That way, there remains only 2 loops; each one is hidden in these functions.

Teuxe
  • 43
  • 1
  • 6