Fortran read оператор чтения за пределами конца строки
знаете ли вы, что следующее утверждение гарантированно соответствует одному из стандартов fortran 90/95/2003? "Предположим, что оператор read для символьной переменной получает пустую строку (т. е. содержит только пробелы и новые символы строки). Если спецификатор формата является звездочкой ( * ), он продолжает считывать последующие строки, пока не будет найдена непустая строка. Если спецификатором формата является ' (A)', то символьная переменная заменяется пустой строкой."
например, пожалуйста, посмотрите на следующую минимальную программу и входной файл.
программный код:
PROGRAM chk_read
INTEGER, PARAMETER :: MAXLEN=30
CHARACTER(len=MAXLEN) :: str1, str2
str1='minomonta'
read(*,*) str1
write(*,'(3A)') 'str1_start|', str1, '|str1_end'
str2='minomonta'
read(*,'(A)') str2
write(*,'(3A)') 'str2_start|', str2, '|str2_end'
END PROGRAM chk_read
входной файл:
----'input.dat' content is below this line----
yamanakako
kawaguchiko
----'input.dat' content is above this line----
обратите внимание, что в 'input есть четыре строки.dat ' и первая и третья строки пусты (содержат только пробелы и символы новой строки). Если я запускаю программу как
$ ../chk_read < input.dat > output.dat
Я получаю следующий вывод
----'output.dat' content is below this line----
str1_start|yamanakako |str1_end
str2_start| |str2_end
----'output.dat' content is above this line----
первый оператор read для переменной "str1", похоже, смотрит на первую строку вход.dat', найдите пустую строку, перейдите ко второй строке, найдите значение символа "yamanakako" и сохраните его в "str1".
напротив, второй оператор read для переменной "str2", похоже, получает третью строку, которая является пустой, и сохраняет пустую строку в "str2", не переходя к четвертой строке.
Я попытался скомпилировать программу Intel Fortran (ifort 12.0.4) и GNU Fortran (gfortran 4.5.0) и получил тот же результат.
немного о предыстории этого вопроса: я пишу подпрограмму для чтения файла данных, который использует пустую строку в качестве разделителя блоков данных. Я хочу убедиться, что пустая строка, и только пустая строка, выбрасывается при чтении данных. Мне также нужно сделать его стандартным и портативным.
Спасибо за вашу помощь.
2 ответов
из проекта стандарта Fortran 2008:
список-направленный вход / выход позволяет редактировать данные в соответствии с типом элемента списка вместо спецификации формата. Он также позволяет данные должны быть свободными, то есть разделенными запятыми (или точками с запятой) или холостые патроны.
затем:
символы в одной или нескольких записях, ориентированных на список, составляют последовательность значений и разделители значений. Конец записи имеет тот же эффект как пустой символ, если он не находится внутри символа постоянный. любая последовательность из двух или более пробелов подряд считается один пробел, если только он не находится внутри символьной константы.
это неявно указывает, что во входных данных, ориентированных на список, пустые строки обрабатываются как пробелы до следующего непустого значения.
при использовании дескриптора формата fmt= '(A) ' при чтении пустые строки считываются в str. С другой стороны, fmt=*, что подразумевает список-направленный ввод-вывод в свободной форме пропускает пустые строки, пока не найдет непустую символьную строку. Чтобы проверить это, сделайте что-то вроде:
PROGRAM chk_read
INTEGER :: cnt
INTEGER, PARAMETER :: MAXLEN=30
CHARACTER(len=MAXLEN) :: str
cnt=1
do
read(*,fmt='(A)',end=100)str
write(*,'(I1,3A)')cnt,' str_start|', str, '|str_end'
cnt=cnt+1
enddo
100 continue
END PROGRAM chk_read
$ cat input.dat
yamanakako
kawaguchiko
EOF
запуск программы дает этот выход:
$ a.out < input.dat
1 str_start| |str_end
2 str_start| |str_end
3 str_start| |str_end
4 str_start|yamanakako |str_end
5 str_start| |str_end
6 str_start|kawaguchiko |str_end
С другой стороны, если вы используете ввод по умолчанию:
read(*,fmt=*,end=100)str
вы в конечном итоге с этим выход:
$ a.out < input.dat
1 str1_start|yamanakako |str1_end
2 str2_start|kawaguchiko |str2_end
эта часть стандартного проекта F2008, вероятно, рассматривает вашу проблему:
10.10.3 List-directed input
7 Когда следующий эффективный элемент имеет тип символа, форма ввода состоит из возможно разделенной последовательности нуля или более rep-char s, параметр типа вида которого подразумевается типом эффективный пункт. Последовательности символов могут быть продолжены с конца одна запись до начала следующей записи, но конец записи не должно происходить между двойным Апострофом в apostrophe-разделенная последовательность символов, ни между двойной кавычкой в последовательности символов с разделителями кавычек. Конец записи не заставляйте пустой или любой другой символ становиться частью последовательность символов. Последовательность символов может быть продолжена на столько записи по мере необходимости. Символы пробел, запятая, точка с запятой, и тире может отображаться в последовательностях символов по умолчанию, ASCII или ISO 10646.