4

I am wondering how could I go from a character array to several character strings. Indeed, I have a character array containing 17 file path. Lets say :

character, dimension(29,17) :: FILE_SIM_all
character, length(29) :: FILE_SIM

! Declarations end

FILE_SIM_all(1:29,1) = "/Users/toto/Documents/toto.nc"
FILE_SIM_all(1:29,2) = etc...

I would like to convert recursively (inside a for loop with sim=1,17) the "sim" row of FILE_SIM_all to a character string. Lets say something like

do sim=1,17
    FILE_SIM(1:29) = FILE_SIM_all(1:29,sim)
enddo

But I'm getting the following error when compilling my program :

error #6366: The shapes of the array expressions do not conform. [FILE_SIM]

What am I doing wrong? Thanks !

T.Des
  • 80
  • 8

1 Answers1

5

Starting with a simpler variant of the problem, to create a character scalar of a certain length from an rank one array of length one characters that has the same size as the certain length, you can use an assignment statement.

! Declare vector to be an rank one array of size ten of 
! length one characters.
CHARACTER(1) :: vector(10)
! Declare scalar to be a character scalar of length ten, 
! so LEN(scalar) == SIZE(vector)
CHARACTER(10) :: scalar
INTEGER :: i     ! Loop index.

! Define `vector`.  Note that the right hand side of the 
! assignment is a rank one array of ten length one characters, 
! consistent with the definition of vector.
vector = (/ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' /)

! Loop over the elements of `vector` and the characters of 
! `scalar` and transfer the individual characters.
DO i = 1, LEN(scalar)  ! or SIZE(vector)
  scalar(i:i) = vector(i)
END DO

(A FORALL statement might be a little more concise, particularly in F2008.)

Your problem simply adds another rank to the above.

! Declare `matrix` to be an rank two array of shape (10,2) of 
! length one characters.
CHARACTER(1) :: `matrix`(10,2)
! Declare `list` to be a rank one array of size 2 and 
! length ten, so LEN(list) == SIZE(matrix,1) and 
! SIZE(list) == SIZE(matrix,2)
CHARACTER(10) :: list(2)
INTEGER :: i     ! Inner Loop index.
INTEGER :: j     ! Outer loop index.

! Define `matrix`.  Note that the right hand side of each 
! assignment is a rank one array of ten length one characters, 
! consistent with the definition of a column of matrix.
matrix(:,1) = (/ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' /)
matrix(:,2) = (/ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' /)

! Loop over the columns of matrix and the elements of list.
DO j = 1, SIZE(list)   ! or SIZE(matrix,1)
  ! Loop over the rows of `matrix` and the characters of 
  ! an element of `list` and transfer the individual characters.
  DO i = 1, LEN(list)   ! or SIZE(matrix,2)
    list(j)(i:i) = matrix(i,j)
  END DO
END DO

Note that a scalar in Fortran is very distinct from an array. If you assign a scalar to an array, you assign the value of that scalar to every element in the array, as if you had written arrary(1) = scalar ; array(2) = scalar ; ...

Note also that intrinsic character assignment truncates (or pads) if the length of the right hand side does not match the length of the left hand side.

Hence in your code:

FILE_SIM_all(1:29,1) = "/Users/toto/Documents/toto.nc"

which assigns a scalar to an array section, does not do anything useful, unless you want 29 single slash characters!

The error message in your example arises because you are trying to assign an array section of size 29 to a scalar (that happens to be a character object of length 29). In general, you cannot assign arrays (rank of one or greater) to scalars (rank of zero).

IanH
  • 21,026
  • 2
  • 37
  • 59