На само деле С (char) - это всего 1 символ, так что правильнее говорить об элементе данных большей длины, но с внутренним типом C - например CHAR10. Фактически CHAR10 - это "статический" массив из 10 символов типа C, в тоже время STRING - это "динамический" массив ( то есть с переменной длиной) символов типа C.
Рассмотрим следующий код:
DATA lv_char TYPE char10 VALUE '12345'.
DATA lv_str TYPE string VALUE '12345'.
Здесь переменная lv_char хранит значение, равное '12345 '- то есть символы от 1 до 5 и еще 5 пробелов, потому что у нее фиксированная длина 10 символов. Переменная lv_str хранит только символы '12345'.
А теперь следующий код:
DATA lv_char TYPE char10 VALUE space.
DATA lv_str TYPE string VALUE space.
space - это заменитель ' '.
Здесь переменная lv_char хранит значение, равное 10 пробелам. Переменная lv_str хранит '', то есть ничего. Не один пробел, а именно ничего. Длина строки = 0.
Ну с lv_char думаю все понятно. Почему lv_str не хранит пробел?
Потому что мы инициализируем ее символьным литералом (символьной константой) - то есть неким набором символом (в данном случае пробелом), заключенным между одинарных кавычек. Прикол в том, что в символьных литералах граничные пробелы удаляются. Поскольку у нас ничего кроме пробела нет, то строка в итоге ничего и не хранит.
Рассмотрим пример, в котором проявляются особенности переменных типа CHAR* и сжатия пробелов.
Допустим у нас извне приходит некое значение в переменной lv_char типа CHAR10 - пользователь что-то вводит, IDOC пришел - что угодно. Нам нужно проверить, что это значение содержит только цифры. Если это не так, выдавать ошибку, писать логи - что угодно. Не суть важно.
Как это можно проверить? Например, так:
IF lv_char CO '0123456789'.
"только цифры.
ELSE.
"что-то еще
ENDIF.
Теперь допустим нам приходит в переменной lv_char число 42. Но после проверки мы попадаем в ветку ELSE. Удивительно? На первый взгляд да - ведь в переменной только цифры 4 и 2, проверка должна проходить. Но потом становится понятно, что на самом деле не только 4 и 2, а еще и 8 пробелов. Ладно, меняем условие на такое, что в переменной допускаются цифры и пробелы:
IF lv_char CO '0123456789 '. "После 9 стоит пробел
Но программа все равно упорно лезет в ветку ELSE. Ну поскольку про сжатие пробелов Вы уже в курсе, то можете догадаться, что наш трюк с добавлением пробела не сработал, потому что компилятор его все равно выкинул и в итоге в скомпилированном коде у нас все также проверка на 1-9. О пробелах ни слова, ни байта.
Ну это все замечательно, но что делать? Вариантов несколько:
- Поставить пробел не в конце, а, например, посередине:
IF lv_char CO '01234 56789'. "После 4 стоит пробел.
Поможет в данном случае, поскольку пробелы нам фактически не нужны - мы просто обходим особенность CHAR, но могут быть случаи, когда пробел ключевая фигура - ниже я приведу пример. - Помещать lv_char предварительно в переменную типа string. Это также прокатит, если вам фактически пробел не нужен. Но если нужен - то нет. Причем в отличии от п.1 это еще и лишняя переменная, лишнее присвоение, да и лишняя писанина.
- Использовать не символьный литерал, а строковый. Строковый в коде задается набором символов ограниченным апострофами (на русской клавиатуре он обычно на кнопке с буквой Ё). Напомню, символьный ограничивается одинарной кавычкой (на кнопке с Э). В строковых литералах пробелы НЕ сжимаются - что ввели, то и будет в коде. То есть, в нашем примере код может быть таким:
IF lv_char CO `0123456789 `. "После 9 стоит пробел
Теперь обещанный пример, когда пробел ключевая фигура. Задача найти первую позицию с пробелом в строке . Пишем например так:
FIND ' ' IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length.
В результате в lv_offset у нас будет 0, а не ожидаемое 5. Почему? Все потому же - ' ' сжался до пустого места, а пустое место у нас где угодно, а первое пустое место в начале строки. Оба первых пункта из решения выше нам не подойдут здесь, только 3ий:
FIND ` ` IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length.
FIND ' ' IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length.
В результате в lv_offset у нас будет 0, а не ожидаемое 5. Почему? Все потому же - ' ' сжался до пустого места, а пустое место у нас где угодно, а первое пустое место в начале строки. Оба первых пункта из решения выше нам не подойдут здесь, только 3ий:
FIND ` ` IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length.