Reading Non-tabular Numeric Values from a Text File à la Fortran's `read`

I need to read off some ASCII numeric output from some legacy (Fortran 77) code. The kind of text file the legacy code produces follow a regular, but non-rectangular/non-tabular pattern.

Specifically, the text files look a bit like this:

header line
         1    27
  0.31622777E-02  0.50118723E-02  0.79432823E-02  0.12589254E-01  0.19952623E-01
  0.31622777E-01  0.50118723E-01  0.79432823E-01  0.12589254E+00  0.19952623E+00
  0.31622777E+00  0.50118723E+00  0.79432823E+00  0.12589254E+01  0.19952623E+01
  0.31622777E+01  0.50118723E+01  0.79432823E+01  0.12589254E+02  0.19952623E+02
  0.31622777E+02  0.50118723E+02  0.79432823E+02  0.12589254E+03  0.19952623E+03
  0.31622777E+03  0.50118723E+03
 -0.28388501E+00  0.10413154E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
 -0.66297354E+00  0.35262146E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
 -0.29740949E-02  0.10717386E-01 -0.22316197E-01  0.35029609E-01 -0.46499344E-01
  0.55688680E-01 -0.62842348E-01  0.48634572E-01 -0.67797324E-01  0.69972176E-01
 -0.73602358E-01  0.71295548E-01 -0.70866853E-01  0.69768476E-01 -0.68716222E-01
  0.28859793E-01 -0.67162380E-01  0.50450533E-01 -0.35435385E-01  0.13516383E-01
  0.18711469E-01 -0.64717484E-01  0.12754612E+00 -0.21093939E+00  0.34453871E+00
 -0.32500623E+01 -0.67359405E-01
  0.58938642E-02 -0.21211666E-01  0.44120793E-01 -0.69211421E-01  0.91907070E-01
 -0.11039448E+00  0.12605537E+00 -0.56226447E-01  0.13242614E+00 -0.14161286E+00
 -0.16303272E+00 -0.13667999E+00  0.14174303E+00 -0.14587339E+00  0.14867014E+00
 -0.20501332E+00  0.12836507E+00 -0.15900480E+00  0.17494237E+00 -0.19615537E+00
  0.22656960E+00 -0.26964107E+00  0.32868746E+00 -0.41003234E+00  0.56129618E+00
 -0.46931739E+01 -0.91527285E-01
  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00  0.00000000E+00
  0.00000000E+00  0.00000000E+00
         2    27
  0.31622777E-02  0.50118723E-02  0.79432823E-02  0.12589254E-01  0.19952623E-01
  0.31622777E-01  0.50118723E-01  0.79432823E-01  0.12589254E+00  0.19952623E+00
  0.31622777E+00  0.50118723E+00  0.79432823E+00  0.12589254E+01  0.19952623E+01
  0.31622777E+01  0.50118723E+01  0.79432823E+01  0.12589254E+02  0.19952623E+02
  0.31622777E+02  0.50118723E+02  0.79432823E+02  0.12589254E+03  0.19952623E+03
  0.31622777E+03  0.50118723E+03
 -0.99066638E+00  0.45725969E-01  0.00000000E+00  0.00000000E+00 -0.61186836E+00
 -0.27653707E+01 -0.50076368E+00  0.00000000E+00  0.00000000E+00 -0.19906894E+01
 -0.64481571E-03 -0.28811284E-03 -0.11125193E-03  0.57927026E-03 -0.10793654E-02
  0.15721588E-02 -0.23300617E-02 -0.66582251E-01  0.23707637E-02 -0.43395041E-02
  0.11915275E-01 -0.27845191E+00 -0.59483502E-01 -0.13212460E+00 -0.31526855E-01
  0.10918047E-01 -0.11908214E-01  0.53361024E-02 -0.67288190E-02  0.37736690E-02
  0.57131860E-03 -0.64662998E-02  0.13752021E-01 -0.21374852E-01  0.26936841E-01
 -0.76688323E+00  0.58611779E-01
  0.52676302E-03  0.49798849E-03 -0.55166437E-03  0.73323831E-03 -0.94228643E-03
  0.99377974E-03 -0.42667798E-03  0.41399578E-01 -0.12620187E-03 -0.29863328E-02
  0.67765439E-02  0.10414210E+00  0.10370732E+00 -0.19347510E+01 -0.12097262E+00
 -0.21702603E-02 -0.47386586E-01  0.15576480E-01 -0.82690514E-02 -0.11405487E-01
  0.38762702E-01 -0.75350382E-01  0.12027346E+00 -0.16718289E+00  0.20320646E+00
 -0.47896020E+01  0.36510209E+00
 -0.55681033E-04 -0.69320527E-04  0.71740126E-04 -0.64186266E-04  0.47361628E-04
 -0.29082510E-04 -0.15852182E-03 -0.47678740E-01  0.41029015E-02 -0.66330423E-02
  0.15093701E-01 -0.30889848E+00 -0.63553313E-01 -0.13159518E+00 -0.24756785E-01
  0.36308927E-01 -0.84059222E-02 -0.82833142E-03  0.12365533E-04 -0.63963186E-02
  0.15730544E-01 -0.28344459E-01  0.43750909E-01 -0.59398651E-01  0.69753232E-01
  0.18921689E+01  0.14586077E+00
  0.60525677E+00  0.16867615E+00  0.00000000E+00  0.00000000E+00  0.59864512E+00
  0.19244643E+01  0.91647124E+00  0.00000000E+00  0.00000000E+00  0.18582393E+01
  0.32937530E-04  0.15715882E-04  0.24996037E-04 -0.97784745E-04  0.18911520E-03
 -0.26998034E-03  0.43462189E-03  0.36105880E-01 -0.31377737E-02  0.57508252E-02
 -0.14600244E-01  0.34077089E+00  0.76238192E-01  0.12491533E+00  0.34003922E-01
 -0.30530815E-01  0.37928839E-01 -0.19537756E-01  0.42079058E-01 -0.59269632E-01
  0.83197505E-01 -0.11534374E+00  0.15438187E+00 -0.19359020E+00  0.21954921E+00
 -0.63592060E+00  0.41400244E+00
 -0.15231629E-04 -0.10170508E-03  0.25751737E-03 -0.52520193E-03  0.86142873E-03
 -0.11547992E-02  0.11560776E-02 -0.22999569E-01  0.17941328E-02 -0.88175219E-03
  0.71987567E-03 -0.14490451E+00 -0.90848912E-01  0.17592991E+01  0.14265548E+00
 -0.16360208E+00  0.13899006E+00 -0.12757394E+00  0.22245974E+00 -0.32490687E+00
  0.47035670E+00 -0.66674430E+00  0.90626197E+00 -0.11490476E+01  0.13166895E+01
 -0.39829001E+01  0.24281685E+01
  0.10306336E-04 -0.38526377E-04  0.12317492E-03 -0.26214645E-03  0.42886950E-03
 -0.57303805E-03  0.71523992E-03  0.24527144E-01 -0.21674551E-02  0.48632541E-02
 -0.14101297E-01  0.37263693E+00  0.88928167E-01  0.11823001E+00  0.43256365E-01
 -0.24757761E-01  0.67456241E-01 -0.39908647E-01  0.84175467E-01 -0.12494035E+00
  0.18212994E+00 -0.25903569E+00  0.35251756E+00 -0.44658103E+00  0.50885311E+00
  0.62033620E+00  0.97386213E+00
  ... and so on ...

(Regarding the “1 27”, “2 27”, …, the first number is just a counter, up to some integer n. The second number is how many values are in each group, of which there are 4 or 7; there are two places where another group of 10 numbers are in between some of these 4 or 7 groups. Confusing, I know.)

In more-modern Fortran, one would read this file like this (after open(unit = 2, ...)):

! Read off the header line without storing.
read(2, *) ! read from channel 2, in whatever format.
do i = 1, n
    ! Read and store the counter, number-of-values pair
    read(2, *) counter(i), num_var(i)

    ! Read and store the first group of num_var (e.g. 27) values
    read(2, *) (var1(j, counter(i)), j = 1, num_var(i))

    ! Read and store the 10 values in between groups of num_var values.
    read(2, *) var2(1, counter(i)), var2(2, counter(i)), uselessvar1, uselessvar2, var2(3, counter(i))
    read(2, *) var3(1, counter(i)), var3(2, counter(i)), uselessvar1, uselessvar2, var3(3, counter(i))

    ! Read and store the next group of num_var (e.g. 27) values.
    read(2, *) (var4(j, counter(i)), j = 1, num_var(i))
    
    ! ... so on and so forth ...

enddo

Is there a “Julia way” of reading text files by following the buffer (which can parse numerical values separated by mixtures of space, tab, or a new line) value-by-value and assigning them, also value-by-value to their respective variables?

The read, readuntil, readdlm, … functions do not seem to work in this manner.

I have done some searching, both here and elsewhere on the internet, but did not find anyone asking this before (to my surprise). Either that’s because no one needed to deal with old Fortran-produced text files, or because I am missing something trivial…

Any advice or ideas would be greatly appreciated. Thank you!

I think something like this would work:

test.dat is the file

1 2   3 4   5
1 2
file = open("test.dat","r")
x1 = parse.(Int64,split(readline(file), char -> char <= ' ', keepempty=false))
x2 = parse.(Int64,split(readline(file), char -> char <= ' ', keepempty=false))
close(file)

x1 will contain the data of the first line, x2 of the second line. Of course you can add
a loop to run over the lines of the file. (The parse function is broadcasted by the “.”).

(edited, such that the split function can be used with multiple spaces or tabs).

1 Like

Actually that will be useful to me as well, so I would do it this way:

julia> lineparser( t :: Type, s :: String ) = parse.(t,split(s, c -> c <= ' ', keepempty=false))

julia> file = open("teste.dat","r")
IOStream(<file teste.dat>)

julia> lineparser(Int64,readline(file))
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

julia> x2 = lineparser(Float64,readline(file))
2-element Array{Float64,1}:
 1.0
 2.0
1 Like

Thank you!! This indeed solves the problem when wrapped in a loop to move across each line to assign the values.