Hi,
The i0 format is only a part of the solution of the problem.
The i0 format is what we have, but what we need is dynamic
strings.
Of course, when you simply want to write a string directly on
an external logical unit, the format works perfectly :
program testformati0
implicit none
write ( * , "(a,i0,a)" ) """", 2008 , """"
end program testformati0
writes out :
"2008"
But what if you want to process the string ?
The simplest way would be to store the integer into a
string, so that this string is available for another use
(like concatenating the month for example).
If you simply declare the string with a static
length and write into it as an internal file,
you loose all the benefit of the i0 format :
program testformati0
use string
implicit none
character(len=3D10) :: mystring
write ( mystring , "(i0)" ) 2008
write ( * , * ) """", mystring , """"
end program testformati0
prints out :
"2008 "
as expected, because the string is of length 10 :
the blanks are added at the end of the string.
Of course, one may add "trim" :
program testformati0
use string
implicit none
character(len=3D10) :: mystring
write ( mystring , "(i0)" ) 2008
write ( * , * ) """", trim(mystring) , """"
end program testformati0
prints out :
"2008"
since the "trim" intrinsic remove all trailing blanks.
The problem is that one would like to have a dynamic
string which length would be computed dynamically
depending on the integer to represent.
There are not so many ways to do it in standard fortran and without
using any external module or library or C (or sorcery)
The solution I know is to use an automatic array, which length is
computed
depending on the number of characters which are necessary
to represent the integer as a string.
One solution is to create a routine which takes the trimmed
formatted string as an argument :
program testformati0
use string
implicit none
character(len =3D 10 ) :: mystring
write ( mystring , "(i0)" ) 2008
call writestring ( trim(mystring) )
contains
subroutine writestring ( mystring )
character(len=3D*) , intent (in) :: mystring
write ( * , * ) """", mystring , """"
end subroutine writestring
end program testformati0
which prints out :
"2008"
This is because the automatic array in the writestring routine
is of size "4".
This trick is explained in the Flibs web page of Arjen Markus :
http://flibs.sourceforge.net/fortran_aspects.html
But what if we want to define a routine which takes the integer
as the argument ?
One may define the following module :
module string
contains
pure function compute_charnb ( value ) result ( nbchar )
integer , intent (in) :: value
integer :: nbchar
integer :: valueanalyzed
if (value < 0) then
nbchar =3D 2
valueanalyzed =3D - value
else
nbchar =3D 1
valueanalyzed =3D value
end if
do
if ( valueanalyzed < 10 ) then
exit
endif
valueanalyzed =3D valueanalyzed / 10
nbchar =3D nbchar + 1
end do
end function compute_charnb
end module string
The compute_charnb algorithm can be found in approximately
the same form in the obtfmt.f90 source code of Michel Olagnon :
ftp://ftp.ifremer.fr/ifremer/ditigo/fortran90/obtfmt.f90
In another form, it is defined in the Fox xml reader/writer
of Toby White, in the module fox_m_fsys_format,
n =3D int(log10(real(max(abs(i),1)))) + 1 + dim(-i,0)/max(abs(i),1)
or in base "b" :
n =3D int(log10(real(max(abs(i),1)))/log10(real(b)))+ 1 + dim(-i,0)/
max(abs(i),1)
Now that one have the compute_charnb routine, one can
define an automatic array with dynamic length thanks to
the character(len=3Dcompute_charnb(value)) statement. But
this cannot be done directly in the main program :
program testformati0
use string
implicit none
character(len =3D compute_charnb ( 2008 )) :: mystring
write ( mystring , "(i0)" ) 2008
write ( * , * ) """", mystring , """"
end program testformati0
generates the error :
Error: An automatic object is invalid in a main program.
with my Intel Fortran v8.
One has instead to define a subroutine which takes the
value as an argument :
program testformati0
use string
implicit none
call read_string ( 2008 )
contains
subroutine writestring ( value )
integer , intent (in) :: value
character(len =3D compute_charnb ( value )) :: mystring
write ( mystring , "(i0)" ) 2008
write ( * , * ) """", mystring , """"
end subroutine writestring
end program testformati0
and that finally prints out :
"2008"
as expected, since the string is of length 4.
Booo, this is complicated.
Really, the "i0" format is what we have, but what we
need is a dynamic string.
So I looked at the iso_varying_string module :
http://www.fortran.com/iso_varying_string.f95
but I did not see anything about string formatting.
What we really need is the following :
type ( varying_string ) :: mystring
mystring =3D stringformat ( 2008 )
call stringprint ( mystring )
but we do not have this in standard fortran.
Any other idea ?
Regards,
Micha=EBl Baudin


|