string - vez - Convierte enteros en cadenas para crear nombres de archivos de salida en tiempo de ejecuciĆ³n
leer una linea especifica de un archivo en python (9)
Tengo un programa en Fortran que guarda los resultados en un archivo. En este momento abro el archivo usando
OPEN (1, FILE = ''Output.TXT'')
Sin embargo, ahora quiero ejecutar un ciclo y guardar los resultados de cada iteración en los archivos ''Output1.TXT''
, ''Output2.TXT''
, ''Output3.TXT''
, y así sucesivamente.
¿Hay alguna manera fácil en Fortran de construir nombres de archivo desde el contador de bucles?
Aquí está mi enfoque de subrutina para este problema. transforma un entero en el rango 0: 9999 como un personaje. Por ejemplo, INTEGER 123 se transforma en el personaje 0123. Espero que ayude.
PD: perdón por los comentarios; tienen sentido en rumano: P
subroutine nume_fisier (i,filename_tot)
implicit none
integer :: i
integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii
character(1) :: filename1,filename2,filename3,filename4
character(4) :: filename_tot
! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar
! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate.
if(i<=9) then
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+0)
filename4=char(48+i)
elseif(i>=10.and.i<=99) then
integer_zeci=int(i/10)
rest_zeci=mod(i,10)
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=100.and.i<=999) then
integer_sute=int(i/100)
rest_sute=mod(i,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+0)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=1000.and.i<=9999) then
integer_mii=int(i/1000)
rest_mii=mod(i,1000)
integer_sute=int(rest_mii/100)
rest_sute=mod(rest_mii,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+integer_mii)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
endif
filename_tot=''''//filename1//''''//filename2//''''//filename3//''''//filename4//''''
return
end subroutine nume_fisier
Bueno, aquí hay una función simple que devolverá la versión de cadena justificada a la izquierda de un entero:
character(len=20) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
Y aquí hay un código de prueba:
program x
integer :: i
do i=1, 100
open(11, file=''Output''//trim(str(i))//''.txt'')
write (11, *) i
close (11)
end do
end program x
Para convertir un entero en una cadena:
integer :: i
character* :: s
if (i.LE.9) then
s=char(48+i)
else if (i.GE.10) then
s=char(48+(i/10))// char(48-10*(i/10)+i)
endif
Para una versión abreviada. Si todos los índices son menores que 10, entonces use lo siguiente:
do i=0,9
fid=100+i
fname=''OUTPUT''//NCHAR(i+48) //''.txt''
open(fid, file=fname)
!....
end do
Para una versión general:
character(len=5) :: charI
do i = 0,100
fid = 100 + i
write(charI,"(A)"), i
fname =''OUTPUT'' // trim(charI) // ''.txt''
open(fid, file=fname)
end do
Eso es todo.
Pruebe lo siguiente:
....
character(len=30) :: filename ! length depends on expected names
integer :: inuit
....
do i=1,n
write(filename,''("output",i0,".txt")'') i
open(newunit=iunit,file=filename,...)
....
close(iunit)
enddo
....
Donde "..." significa otro código apropiado para su propósito.
Una solución mucho más fácil en mi humilde opinión ...................
character(len=8) :: fmt ! format descriptor
fmt = ''(I5.5)'' ! an integer of width 5 with zeros at the left
i1= 59
write (x1,fmt) i1 ! converting integer to string using a ''internal file''
filename=''output''//trim(x1)//''.dat''
! ====> filename: output00059.dat
Ya lo mostré en otro lugar en SO ( ¿Cómo usar una variable en la declaración de especificador de formato?, No un duplicado exacto en mi humilde opinión), pero creo que vale la pena ubicarlo aquí. Es posible utilizar las técnicas de otras respuestas para esta pregunta para hacer una función simple
function itoa(i) result(res)
character(:),allocatable :: res
integer,intent(in) :: i
character(range(i)+2) :: tmp
write(tmp,''(i0)'') i
res = trim(tmp)
end function
que puede usar después sin preocuparse por recortar y ajustar a la izquierda y sin escribir en una variable temporal:
OPEN(1, FILE = ''Output''//itoa(i)//''.TXT'')
Requiere Fortran 2003 debido a la cadena asignable.
Ya probé con @Alejandro y @ user2361779, pero me da un resultado insatisfecho, como el file 1.txt
o el file 1.txt
file1 .txt
lugar de file1.txt
. Sin embargo, encuentro la mejor solución:
...
integer :: i
character(len=5) :: char_i ! use your maximum expected len
character(len=32) :: filename
write(char_i, ''(I5)'') i ! convert integer to char
write(filename, ''("path/to/file/", A, ".dat")'') trim(adjustl(char_i))
...
Explicación:
por ejemplo, establecer i = 10
y write(char_i, ''(I5)'') i
char_i gives " 10" ! this is original value of char_i
adjustl(char_i) gives "10 " ! adjust char_i to the left
trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right
Creo que esta es la solución más simple que le da un nombre de archivo de longitud dinámica sin ningún espacio en blanco heredado del proceso de conversión de enteros a cadenas.
puedes escribir en una unidad, pero también puedes escribir en una cadena
program foo
character(len=1024) :: filename
write (filename, "(A5,I2)") "hello", 10
print *, trim(filename)
end program
Tenga en cuenta (este es el segundo truco que estaba hablando) que también puede construir una cadena de formato mediante programación.
program foo
character(len=1024) :: filename
character(len=1024) :: format_string
integer :: i
do i=1, 10
if (i < 10) then
format_string = "(A5,I1)"
else
format_string = "(A5,I2)"
endif
write (filename,format_string) "hello", i
print *, trim(filename)
enddo
end program