按索引返回字符串的一个字符的语法

Syntax for Returning One Character of String by Index

我正在尝试比较字符串中的一个字符,看它是否是我的分隔符。但是,当我执行以下代码时,变量 valstring 中的值是一个数字,表示已转换为字符串的字节,而不是字符本身。例如,该值可能是字符串“58”。

通过使用调试功能在 CoDeSys 中进行测试,我知道字符串 sReadLine 包含有效的字符串。我只是不确定只挑出其中一个的语法; sReadLine[valPos + i] 部分我不明白。

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

我想你有多种选择。

1) 改用内置字符串函数。您可以使用 MID 函数获取字符串的一部分。因此,在您的情况下,类似于“从 sReadLine.

中获取 valPos + 1 中的一个字符
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) 将 ASCII 字节转换为字符串。在 TwinCAT 系统中,有一个函数 F_ToCHR。它接受一个 ASCII 字节和 returns 字符作为字符串。我找不到类似 Codesys 的东西,但我确信在某些库中会有解决方案。所以请注意,如果不进行修改,这将无法在 Codesys 中运行:

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) OSCAT library 似乎有一个 CHR_TO_STRING 功能。您可以在第 2 步中使用它代替 F_ToCHR。

4) 可以使用指针将ASCII 字节复制到字符串数组(MemCpy) 并添加一个字符串结束符。这需要一些指针等方面的知识。有关示例,请参见 Codesys forum

5) 你可以自己写一个类似步骤2的辅助函数。检查 the example from Codesys forums。该示例不包含所有字符,因此需要更新。不太优雅。

将字节转换为字符串时,转换的是字节的数字表示形式。 这意味着您将该字节解释为 ascii 字符(: 的 ascii 十进制值为 58)。

所以如果你想连接字符而不是它们的 ascii 十进制表示,你需要另一个函数:

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

编辑:

作为 Quirzo,我无法为 Codesys 找到类似的 F_ToCHR 功能,但您可以轻松地自己构建一个。 例如:

声明部分:

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

实现部分:

F_ASCII_TO_STRING := ascii[input];

正如谢尔盖所​​说,这可能不是您问题的最佳解决方案。似乎您想从初始输入 sReadLine 中提取不包含任何字符 " 的最长子字符串到 valstring,从位置 valPos 开始。 在您的实现中,对于每个有效的输入字符,CONCAT() 需要搜索 valstring 的结尾,然后再向其附加 1 个字符。

你应该分解你的问题并使用两个标准函数来优化:

  • FIND() --> 获取下一个字符的位置"(或者知道有没有none),
  • MID() --> 从初始位置到第一个字符之前(或输入字符串的末尾)创建一个字符串。

这样,就只剩下2个循环了;每一个都隐藏在这些功能中。