Я предполагаю, но, похоже, вы читаете записи переменной длины из файла в запись COBOL фиксированной длины.Мусор в конце записи на COBOL приносит вам немного горя.Трудно сказать, насколько последовательным будет этот мусор от одного чтения к другому (данные за пределами фактической длины входной записи технически не определены).Этот мусор в конечном итоге включается в WS_AMOUNT_TXT
после UNSTRING
. Существует несколько способов решения этой проблемы.Предложение, которое я даю вам здесь, может быть неоптимальным, но оно простое и должно выполнить работу.
Последнее поле INTO
, WS_AMOUNT_TXT
, в вашем выражении UNSTRING
- это то, чтополучает весь конечный мусор.Эту ерунду нужно убрать.Зная, что единственными действительными символами в последнем поле являются цифры и десятичный знак, вы можете очистить его следующим образом:
PERFORM VARYING WS_I FROM LENGTH OF WS_AMOUNT_TXT BY -1
UNTIL WS_I = ZERO
IF WS_AMOUNT_TXT(WS_I:1) IS NUMERIC OR
WS_AMOUNT_TXT(WS_I:1) = '.'
MOVE ZERO TO WS_I
ELSE
MOVE SPACE TO WS_AMOUNT_TXT(WS_I:1)
END-IF
END-PERFORM
Основная идея в приведенном выше коде состоит в том, чтобы сканировать с конца последнегоUNSTRING
поле вывода в начало, заменяющее все, что не является действительной цифрой или десятичной точкой, пробелом.Как только найдена правильная цифра / десятичное число, выйдите из цикла, предполагая, что остальные значения будут действительными.
После очистки используйте встроенную функцию NUMVAL
, как описано в моем ответе на ваш предыдущий вопрос для преобразования WS_AMOUNT_TXT в числовой тип данных.
Один последний совет, MOVE SPACES TO INPUT_REC
перед каждым READ
, чтобы удалить данные, оставшиеся от предыдущего чтения, которые могут остаться в буфере.Это защитит вас при чтении очень «короткой» записи после «длинной» - в противном случае вы можете отключить данные, оставшиеся после предыдущего чтения.
Надеюсь, это поможет.
РЕДАКТИРОВАТЬ Только что заметил этот ответ на ваш вопрос о чтении файлов переменной длины.Использование входной записи переменной длины - лучший подход.Учитывая фактическую длину входной записи, вы можете сделать что-то вроде:
UNSTRING INPUT_REC(1:REC_LEN) INTO...
Где REC_LEN
- переменная, указанная после OCCURS DEPENDING ON
для INPUT_REC
файла FD
.Весь мусор, с которым вы сталкиваетесь, происходит после окончания записи, как определено REC_LEN
.Использование модификации эталона, как показано выше, обрезает его до того, как UNSTRING
выполнит свою работу по выделению отдельных полей данных.
РЕДАКТИРОВАТЬ 2: Невозможно использовать эталонную модификацию с UNSTRING
.Черт ... Это возможно с некоторыми другими диалектами COBOL, но не с OpenVMS COBOL.Попробуйте следующее:
MOVE INPUT_REC(1:REC_LEN) TO WS_BUFFER
UNSTRING WS_BUFFER INTO...
Где WS_BUFFER
- переменная рабочего хранилища PIC X
, достаточно длинная, чтобы содержать самую длинную входную запись.Когда вы MOVE
сокращаете буквенно-цифровое поле на более длинное, поле назначения выравнивается по левому краю с пробелами, используемыми для заполнения оставшегося пространства (т. Е. WS_BUFFER
).Поскольку начальные и конечные пробелы приемлемы для функции NUMVAL
, у вас есть именно то, что вам нужно.
У меня есть причина подтолкнуть вас в этом направлении.Любой мусор, который заканчивается в конце буфера записи при чтении короткой записи, не определен.Существует вероятность того, что часть этого мусора может оказаться цифрой или десятичной точкой.Если это произойдет, процедура очистки, которую я первоначально предложил, завершится неудачей.
РЕДАКТИРОВАТЬ 3: В результирующем WS_AMOUNT_TXT нет ^ @, но все равно есть ^ M
Похоже, файловая система обрабатывает (это ^ M вещь) в конце каждой записи как данные.
Если файл, который вы читаете, получен с платформы Windows итеперь вы читаете его на платформе UNIX, которая объяснит проблему.В Windows записи заканчиваются на , а в UNIX они заканчиваются только на .Файловая система UNIX обрабатывает так, как если бы она была частью записи.
В этом случае вы можете быть почти уверены, что в конце каждой прочитанной записи будет один .,Есть несколько способов справиться с этим:
Метод 1: Как вы уже заметили, предварительно отредактируйте файл с помощью Notepad ++ или другогоинструмент для удаления символов перед обработкой через вашу программу COBOL.Лично я не думаю, что это лучший способ сделать это.Я предпочитаю использовать решение только на языке COBOL, так как оно включает меньше этапов обработки.
Метод 2: Обрежьте последний символ из каждой входной записи перед обработкой.Последний символ всегда должен быть .Попробуйте следующее, если вы читаете записи как переменную длину и имеете фактическую доступную длину входной записи.
SUBTRACT 1 FROM REC_LEN
MOVE INPUT_REC(1:REC_LEN) TO WS_BUFFER
UNSTRING WS_BUFFER INTO...
Метод 3: Обрабатывайте как разделитель при UNSTRINGing следующим образом:
UNSTRING INPUT_REC DELIMITED BY "," OR x"0D"
INTO WS_ID_1, WS_ID_2, WS_CODE, WS_DESCRIPTION, WS_FLAG, WS_AMOUNT_TXT
Метод 4: Условие последнего получающего поля из UNSTRING путем замены конечных нецифровых / нецифровых знаков с пробелами.Я изложил это решение чуть раньше в этом вопросе.Вы также можете изучить оператор INSPECT
, используя параметр REPLACING
(Формат 2).Это должно быть в состоянии сделать почти то же самое - просто замените все x «00» на SPACE и x «0D» на SPACE.
Там, где есть воля, есть путь.Любое из вышеперечисленных решений должно работать на вас.Выберите тот, который вам удобнее всего.