在 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*) 时,我都需要初步(和丑陋的)步骤来执行此操作:

有没有比上面的许多步骤更聪明的解决方案来更优雅地做到这一点?

如果您将字符串分配给比该字符长度短的字符,则会用空格填充。您可以使用它轻松创建具有适当长度的缩进字符。

此外,我使用的所有编译器都理解 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