Синтаксис для возврата одного символа строки по индексу

Я пытаюсь сравнить один символ строки, чтобы увидеть, является ли он моим символом-разделителем. Однако, когда я выполняю следующий код, значение, которое помещается в переменную 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

person Michael LeVan    schedule 07.11.2019    source источник
comment
Можете ли вы объяснить, чего вы хотите достичь? Вы хотите разделить строку разделителем, чтобы создать массив или что? Возможно, есть совсем другое решение вашей задачи, чем просто ответ на проблемный вопрос. Что-то мне подсказывает, что вещь, которую ты хочешь сделать, должна решаться совершенно по-другому.   -  person Sergey Romanov    schedule 08.11.2019


Ответы (3)


Я думаю, у вас есть несколько вариантов.

1) Вместо этого используйте встроенные строковые функции. Вы можете использовать функцию MID, чтобы получить часть нить. Итак, в вашем случае что-то вроде «получить один символ из valPos + 1 из 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) Преобразуйте байт ASCII в строку. В системах TwinCAT есть функция F_ToCHR. Он принимает байт ASCII и возвращает символ в виде строки. Я не могу найти что-то подобное для 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 есть функция CHR_TO_STRING. Вы можете использовать это вместо F_ToCHR на шаге 2.

4) Вы можете использовать указатели для копирования байта ASCII в массив строк (MemCpy) и добавления символа конца строки. Это требует некоторых знаний об указателях и т. д. Примеры см. на форуме Codesys. .

5) Вы можете сами написать вспомогательную функцию, аналогичную шагу 2. Посмотрите пример с форумов Codesys. Этот пример не включает все символы, поэтому его необходимо обновить. Это не совсем элегантно.

person Quirzo    schedule 08.11.2019
comment
Я искал Вариант 1. Спасибо. - person Michael LeVan; 12.11.2019

Когда вы конвертируете байт в строку, преобразуется цифровое представление байта. Это означает, что вы интерпретируете этот байт как символ ascii (десятичное значение ascii : равно 58).

Итак, если вы хотите использовать символы Concat вместо их десятичного представления ascii, вам нужна другая функция:

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

РЕДАКТИРОВАТЬ:

Как Quirzo, я не смог найти аналогичную функцию F_ToCHR для Codesys, но вы могли бы легко создать ее самостоятельно. Например:

Часть декларации:

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];
person Filippo Boido    schedule 08.11.2019
comment
Спасибо за хороший ответ. Я смог найти удовлетворительное решение, создав собственную функцию charAt. Однако я использовал комбинацию функций LEFT и RIGHT следующим образом: charAt := RIGHT(STR := str, SIZE := LEN(STR := str) - index + 1); charAt:= LEFT(STR:= charAt, SIZE:= 1); Мне нравится ваш ответ, так как он фактически преобразует байт в ascii. Спасибо за ваш ответ, но я отдал должное Квирзо, поскольку его вариант 1 был именно тем, что я искал. - person Michael LeVan; 12.11.2019

Как сказал Сергей, это может быть не оптимальным решением вашей проблемы. Похоже, вы хотите извлечь самую длинную подстроку, не содержащую никаких символов, из начального ввода sReadLine в valstring, начиная с позиции valPos. В вашей реализации для каждого допустимого входного символа CONCAT() необходимо искать конец valstring, прежде чем добавив к нему только 1 символ.

Вы должны скорее разложить свою проблему и использовать две стандартные функции, чтобы быть оптимальными:

  • НАЙТИ() --> чтобы получить позицию следующего символа " (или узнать, если ее нет),
  • MID() --> для создания строки от начальной позиции до первого символа " (или конца входной строки).

Таким образом, останется всего 2 петли; каждый из них скрыт в этих функциях.

person Teuxe    schedule 07.04.2020