从 txt 中读取科学格式的数字
Read scientific formatted numbers from txt
我想从一个 txt 文件中读取和存储科学格式的数字,该文件是格式化的,数字由制表符分隔。
这是我目前拥有的:
IMPLICIT NONE
REAL,ALLOCATABLE,DIMENSION(2) :: data(:,:)
INTEGER :: row,column
INTEGER :: j,i
CHARACTER(len=30) :: filename
CHARACTER(len=30) :: format
filename='data.txt'
open(86,file=filename,err=10)
write(*,*)'open data file'
read(86, *) row
read(86, *) column
allocate(data(row,column))
format='(ES14.7)'
do i=1,row
read(86,format) data(i,:)
enddo
close(86)
txt 文件如下所示:
200
35
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35 ...
问题是它没有从 txt 读取正确的值并将其存储到数据变量。是格式问题吗?
我也想知道在这种情况下如何计算列数。 (我可以通过在 for 循环中使用 read(86,*) 来计算行数。)
是的,您的格式不适合您显示的数据。更好的应该是这样read(99,'(6(E11.4,X))') myData(i,:)
。
但是,我不确定您是否真的需要在阅读时使用格式。
以下示例非常接近您尝试做的事情,并且它正在使用和不使用格式的机器人。
program readdata
implicit none
real, allocatable :: myData(:,:)
real :: myLine
integer :: i, j, myRow, myColumn
character(len=30) :: myFileName
character(len=30) :: myFormat
myFileName='data.dat'
open(99, file=myFileName)
write(*,*)'open data file'
read(99, *) myRow
read(99, *) myColumn
allocate(myData(myRow,myColumn))
do i=1,myRow
read(99,*) myData(i,:)
!read(99,'(6(E11.4,X))') myData(i,:)
print*, myData(i,:)
enddo
close(99)
end program readdata
为了测试,我假设文件中始终有行和列,正如您提供的那样,所以我的测试数据如下。
2
6
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35
如果您真的有兴趣使用某种格式读取文件,并且如果列数不是常量,您可能需要一种取决于变量的格式,请参阅相关讨论 here。
虽然没有直接的命令来计算一行中的项目数,但我们可以使用scan命令来计算句点数或(E|e|D|d)。例如,
program main
implicit none
character(100) str
integer n
read( *, "(a)" ) str
call countreal( str, n )
print *, "number of items = ", n
contains
subroutine countreal( str, num )
implicit none
character(*), intent(in) :: str
integer, intent(out) :: num
integer pos, offset
num = 0
pos = 0
do
offset = scan( str( pos + 1 : ), "." ) !! (1) search for periods
!! offset = scan( str( pos + 1 : ), "EeDd" ) !! (2) search for (E|e|D|d)
if ( offset > 0 ) then
pos = pos + offset
num = num + 1
print *, "pos=", pos, "num=", num !! just for check
else
return
endif
enddo
endsubroutine
end
请注意,模式 (1) 仅在所有项都有句点时有效,而模式 (2) 仅在所有项都有指数时有效:
# When compiled with (1)
$ echo "2.9900 2.8000E-35 2.6300D-35 2.46 2.31" | ./a.out
pos= 2 num= 1
pos= 10 num= 2
pos= 22 num= 3
pos= 34 num= 4
pos= 40 num= 5
number of items = 5
# When compiled with (2)
$ echo "2.9900E-35 2.8000D-35 2.6300e-35 2.4600d-35" | ./a.out
pos= 7 num= 1
pos= 19 num= 2
pos= 31 num= 3
pos= 43 num= 4
number of items = 4
对于更一般的用途,编写自定义 "split()" 函数以用空格分隔项目(或使用支持拆分函数的外部库)可能更方便。
我想从一个 txt 文件中读取和存储科学格式的数字,该文件是格式化的,数字由制表符分隔。
这是我目前拥有的:
IMPLICIT NONE
REAL,ALLOCATABLE,DIMENSION(2) :: data(:,:)
INTEGER :: row,column
INTEGER :: j,i
CHARACTER(len=30) :: filename
CHARACTER(len=30) :: format
filename='data.txt'
open(86,file=filename,err=10)
write(*,*)'open data file'
read(86, *) row
read(86, *) column
allocate(data(row,column))
format='(ES14.7)'
do i=1,row
read(86,format) data(i,:)
enddo
close(86)
txt 文件如下所示:
200
35
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35 ...
问题是它没有从 txt 读取正确的值并将其存储到数据变量。是格式问题吗?
我也想知道在这种情况下如何计算列数。 (我可以通过在 for 循环中使用 read(86,*) 来计算行数。)
是的,您的格式不适合您显示的数据。更好的应该是这样read(99,'(6(E11.4,X))') myData(i,:)
。
但是,我不确定您是否真的需要在阅读时使用格式。
以下示例非常接近您尝试做的事情,并且它正在使用和不使用格式的机器人。
program readdata
implicit none
real, allocatable :: myData(:,:)
real :: myLine
integer :: i, j, myRow, myColumn
character(len=30) :: myFileName
character(len=30) :: myFormat
myFileName='data.dat'
open(99, file=myFileName)
write(*,*)'open data file'
read(99, *) myRow
read(99, *) myColumn
allocate(myData(myRow,myColumn))
do i=1,myRow
read(99,*) myData(i,:)
!read(99,'(6(E11.4,X))') myData(i,:)
print*, myData(i,:)
enddo
close(99)
end program readdata
为了测试,我假设文件中始终有行和列,正如您提供的那样,所以我的测试数据如下。
2
6
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35
2.9900E-35 2.8000E-35 2.6300E-35 2.4600E-35 2.3100E-35 2.1600E-35
如果您真的有兴趣使用某种格式读取文件,并且如果列数不是常量,您可能需要一种取决于变量的格式,请参阅相关讨论 here。
虽然没有直接的命令来计算一行中的项目数,但我们可以使用scan命令来计算句点数或(E|e|D|d)。例如,
program main
implicit none
character(100) str
integer n
read( *, "(a)" ) str
call countreal( str, n )
print *, "number of items = ", n
contains
subroutine countreal( str, num )
implicit none
character(*), intent(in) :: str
integer, intent(out) :: num
integer pos, offset
num = 0
pos = 0
do
offset = scan( str( pos + 1 : ), "." ) !! (1) search for periods
!! offset = scan( str( pos + 1 : ), "EeDd" ) !! (2) search for (E|e|D|d)
if ( offset > 0 ) then
pos = pos + offset
num = num + 1
print *, "pos=", pos, "num=", num !! just for check
else
return
endif
enddo
endsubroutine
end
请注意,模式 (1) 仅在所有项都有句点时有效,而模式 (2) 仅在所有项都有指数时有效:
# When compiled with (1)
$ echo "2.9900 2.8000E-35 2.6300D-35 2.46 2.31" | ./a.out
pos= 2 num= 1
pos= 10 num= 2
pos= 22 num= 3
pos= 34 num= 4
pos= 40 num= 5
number of items = 5
# When compiled with (2)
$ echo "2.9900E-35 2.8000D-35 2.6300e-35 2.4600d-35" | ./a.out
pos= 7 num= 1
pos= 19 num= 2
pos= 31 num= 3
pos= 43 num= 4
number of items = 4
对于更一般的用途,编写自定义 "split()" 函数以用空格分隔项目(或使用支持拆分函数的外部库)可能更方便。