在 Fortran 中使用调整后的(增量)缩进写入文件
Write to file with adjusted (incremental) indentation in Fortran
在 Fortran 90
程序中有许多嵌套子程序,我想将这些子程序的嵌套级别打印到一个缩进长度与级别成比例的文件中(即,在嵌套子程序中打印的信息具有更高的缩进比调用的)。
将写入包括不同数据类型的附加信息(字符串、整数……)。
我考虑了不同的方法来做到这一点(在这个例子中,lev
是级别,只是在一个循环中构建,但它在每个子程序中都会更新):
Program adaptIndent
INTEGER :: lev
CHARACTER (LEN=*), PARAMETER :: fmt1 = '(I1,'': ''A)'
CHARACTER (LEN=*), PARAMETER :: fmt2 = '(I2,'': ''A)'
DO lev=1,10
CALL printindent1
!CALL printindent2
!CALL printindent3
ENDDO
CONTAINS
SUBROUTINE printindent1 !convert everything (incl. indent and lev) to CHAR
CHARACTER(LEN=lev) :: indent
CHARACTER(LEN=2) :: strlev
WRITE(indent, '(A)') ' '
WRITE(strlev, '(I2)') lev
WRITE(*, '(A)') indent//TRIM(ADJUSTL(strlev))//': this is my level'
END SUBROUTINE printindent1
SUBROUTINE printindent2 !build a new format defining the indentation
CHARACTER(LEN=2) :: strlev
CHARACTER(LEN=20) :: fmtlev
WRITE(strlev, '(I2)') lev
WRITE(fmtlev, '(A)') '('//TRIM(ADJUSTL(strlev))//'X, A)'
WRITE(*, fmtlev) TRIM(ADJUSTL(strlev))//': this is my level'
END SUBROUTINE printindent2
SUBROUTINE printindent3 !add indent as CHAR to an existing format
CHARACTER(LEN=lev) :: indent
WRITE(indent, '(A)') ' '
IF(lev.LT.10) THEN
WRITE(*, fmt1(1:1)//'A,'//fmt1(2:)) indent, lev, 'this is my level'
ELSE
WRITE(*, fmt2(1:1)//'A,'//fmt2(2:)) indent, lev, 'this is my level'
ENDIF
END SUBROUTINE printindent3
END Program adaptIndent
这些解决方案的(期望)输出是相同的:
1: this is my level
2: this is my level
3: this is my level
4: this is my level
5: this is my level
6: this is my level
7: this is my level
8: this is my level
9: this is my level
10: this is my level
我的问题是,每次我执行有用的 WRITE(*, *fmt*)
时,我都需要初步(和丑陋的)步骤来执行此操作:
- 将缩进计算为一个字符,并在解决方案 1 中将所有内容转换为 CHAR;
- 在解决方案 2 中使用适当数量的前导空格定义新格式;
- 在解决方案 3 中调整现有格式以将缩进包含为 CHAR(请注意,这里的问题更多:是否有一种方法可以定义唯一格式来写入任何大小的整数,而没有任何尾随或前导空格?)
有没有比上面的许多步骤更聪明的解决方案来更优雅地做到这一点?
如果您将字符串分配给比该字符长度短的字符,则会用空格填充。您可以使用它轻松创建具有适当长度的缩进字符。
此外,我使用的所有编译器都理解 I0
格式描述符,这意味着:根据需要使用尽可能多的字符。
这是我的想法:
program printindent_test
implicit none
integer :: i
character(len=20) :: s
do i = 1, 10
call printindent("This is my level", i)
end do
contains
subroutine printindent(str, lev)
implicit none
character(len=*), intent(in) :: str
integer, intent(in) :: lev
character(len=lev) :: indent
indent = ''
write(*, '(A, I0, ": ", A)') indent, lev, str
end subroutine printindent
end program printindent_test
您也不必进行如此多的转换即可获得格式字符串。
write(fmtlev, "('('I2'X,I0,A)')") lev
write(*, fmtlev) lev, ": this is my level"
同样有效。
如果您的编译器不理解 I0
格式,您可以手动执行如下操作:
write(to_write, '(I2, ": ", A)') lev, str
write(*, '(2A)') indent, TRIM(ADJUSTL(to_write))
当然你必须创建一个新的适当大小的临时字符变量:
character(len=4+LEN_TRIM(str)) :: to_write
您可以使用内部函数 REPEAT
然后这样写:
write(*,"(A,I0,A)")repeat(" ",lev),lev, str
在 Fortran 90
程序中有许多嵌套子程序,我想将这些子程序的嵌套级别打印到一个缩进长度与级别成比例的文件中(即,在嵌套子程序中打印的信息具有更高的缩进比调用的)。
将写入包括不同数据类型的附加信息(字符串、整数……)。
我考虑了不同的方法来做到这一点(在这个例子中,lev
是级别,只是在一个循环中构建,但它在每个子程序中都会更新):
Program adaptIndent
INTEGER :: lev
CHARACTER (LEN=*), PARAMETER :: fmt1 = '(I1,'': ''A)'
CHARACTER (LEN=*), PARAMETER :: fmt2 = '(I2,'': ''A)'
DO lev=1,10
CALL printindent1
!CALL printindent2
!CALL printindent3
ENDDO
CONTAINS
SUBROUTINE printindent1 !convert everything (incl. indent and lev) to CHAR
CHARACTER(LEN=lev) :: indent
CHARACTER(LEN=2) :: strlev
WRITE(indent, '(A)') ' '
WRITE(strlev, '(I2)') lev
WRITE(*, '(A)') indent//TRIM(ADJUSTL(strlev))//': this is my level'
END SUBROUTINE printindent1
SUBROUTINE printindent2 !build a new format defining the indentation
CHARACTER(LEN=2) :: strlev
CHARACTER(LEN=20) :: fmtlev
WRITE(strlev, '(I2)') lev
WRITE(fmtlev, '(A)') '('//TRIM(ADJUSTL(strlev))//'X, A)'
WRITE(*, fmtlev) TRIM(ADJUSTL(strlev))//': this is my level'
END SUBROUTINE printindent2
SUBROUTINE printindent3 !add indent as CHAR to an existing format
CHARACTER(LEN=lev) :: indent
WRITE(indent, '(A)') ' '
IF(lev.LT.10) THEN
WRITE(*, fmt1(1:1)//'A,'//fmt1(2:)) indent, lev, 'this is my level'
ELSE
WRITE(*, fmt2(1:1)//'A,'//fmt2(2:)) indent, lev, 'this is my level'
ENDIF
END SUBROUTINE printindent3
END Program adaptIndent
这些解决方案的(期望)输出是相同的:
1: this is my level
2: this is my level
3: this is my level
4: this is my level
5: this is my level
6: this is my level
7: this is my level
8: this is my level
9: this is my level
10: this is my level
我的问题是,每次我执行有用的 WRITE(*, *fmt*)
时,我都需要初步(和丑陋的)步骤来执行此操作:
- 将缩进计算为一个字符,并在解决方案 1 中将所有内容转换为 CHAR;
- 在解决方案 2 中使用适当数量的前导空格定义新格式;
- 在解决方案 3 中调整现有格式以将缩进包含为 CHAR(请注意,这里的问题更多:是否有一种方法可以定义唯一格式来写入任何大小的整数,而没有任何尾随或前导空格?)
有没有比上面的许多步骤更聪明的解决方案来更优雅地做到这一点?
如果您将字符串分配给比该字符长度短的字符,则会用空格填充。您可以使用它轻松创建具有适当长度的缩进字符。
此外,我使用的所有编译器都理解 I0
格式描述符,这意味着:根据需要使用尽可能多的字符。
这是我的想法:
program printindent_test
implicit none
integer :: i
character(len=20) :: s
do i = 1, 10
call printindent("This is my level", i)
end do
contains
subroutine printindent(str, lev)
implicit none
character(len=*), intent(in) :: str
integer, intent(in) :: lev
character(len=lev) :: indent
indent = ''
write(*, '(A, I0, ": ", A)') indent, lev, str
end subroutine printindent
end program printindent_test
您也不必进行如此多的转换即可获得格式字符串。
write(fmtlev, "('('I2'X,I0,A)')") lev
write(*, fmtlev) lev, ": this is my level"
同样有效。
如果您的编译器不理解 I0
格式,您可以手动执行如下操作:
write(to_write, '(I2, ": ", A)') lev, str
write(*, '(2A)') indent, TRIM(ADJUSTL(to_write))
当然你必须创建一个新的适当大小的临时字符变量:
character(len=4+LEN_TRIM(str)) :: to_write
您可以使用内部函数 REPEAT
然后这样写:
write(*,"(A,I0,A)")repeat(" ",lev),lev, str