How can modern Fortran navigate a file with double forward slashes between entries, as in the *.obj format? The goal is to extract the vertex index (first entry) and ignore the vertex normal index (second entry).
For example, for this snippet,
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
the goal is to create an array like this:
face ( 1 ) = [297, 298, 296]
face ( 2 ) = [296, 298, 295]
face ( 3 ) = [384, 385, 382]
face ( 4 ) = [384, 382, 383]
Extra points for an answer which would adopt to a richer format like
f a//b//c d//e//f g//h//i j//k//l
The answer for [How to get Wavefront .obj file with 3 faces (traingle) points to a deleted blog. This post [How to read numeric data from a string in FORTRAN was not relevant.
Three references on the *.obj format: Object Files (.obj), B1. Object Files (.obj), Wavefront .obj file
As suggested in the comments, we can replace /
by a space using sed
etc. We can also scan each character one by one in Fortran (see below). We then read in all integers into vals
and select the desired part as vals( 1:6:2 )
. A similar approach can be used for f a//b//c d//e//f ...
etc by changing 1:6:2 to 1:12:3 etc.
[test.f90]
program main
implicit none
character(100) buf
integer vals(10), ios, i
open(10, file="test.dat", status="old")
do
read(10, "(a)", iostat=ios) buf
if (ios /= 0) exit
do i = 1, len(buf)
if (buf(i:i) == "/") buf(i:i) = " " !! replace "/" by " "
enddo
read(buf(2:), *) vals( 1:6 ) !! read all items
print *, vals( 1:6:2 ) !! select items 1, 3, 5
enddo
close(10)
end
[test.dat]
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
$ gfortran test.f90 && ./a.out
297 298 296
296 298 295
384 385 382
384 382 383
Just for fun, here is a similar code in Python, which is shorter thanks to replace()
and split()
. If we have some similar routines, I guess the above code may also become shorter.
dat = []
for line in open("test.dat").readlines():
dat.append( line[1:] .replace("/", " ") .split() [::2] )
import numpy as np
face = np.array(dat, dtype=int)
print(face)
$ python test.py
[[297 298 296]
[296 298 295]
[384 385 382]
[384 382 383]]