Извлечь подстроку из строкового массива Фортрана - PullRequest
0 голосов
/ 27 апреля 2018

Как извлечь подстроку из массива строк Фортрана? Например

program testcharindex
    implicit none
    character(len=10), dimension(5) :: s
    character(len=10), allocatable :: comp(:)
    integer, allocatable  :: i(:), n(:)
    s = (/ '1_E ', '2_S ', '3_E ', '14_E', '25_S' /)
    i = index(s,'_')
    print *,' i = ', i
    n = s(1:i-1) ! or n = s(:i-1)
    comp = s(i+1:)
    print *,' n = ', n
    print *,' comp = ', comp
end program

Компиляция с gfortran выдает ошибку:

testcharindex.f90: 11: 10:

n = s (1: i-1) 1 Ошибка: индекс массива в (1) должен быть скалярным

Есть ли способ избежать цикла do здесь? Если можно извлечь индекс массива строк, я ожидаю, что он сможет извлечь динамически определенную подстроку массива строк (без зацикливания элементов массива). Я слишком оптимистичен?

Ответы [ 3 ]

0 голосов
/ 28 апреля 2018

В случае, если следует избегать цикла и нет других (простых) методов, может быть полезно определить элементарную функцию подстроки и применить ее к массиву строк. Например,

module str_mod
    implicit none
contains
    elemental function substr( s, a, b ) result( res )
        character(*), intent(in) :: s
        integer,      intent(in) :: a, b
        character(len(s)) :: res

        res = s( a : b )
    endfunction
endmodule

program main
    use str_mod
    implicit none
    character(10) :: s( 5 )
    integer, allocatable :: ind(:)
    character(len(s)), allocatable :: comp(:)

    s = [ '1_E ', '2_S ', '3_E ', '14_E', '25_S' ]
    ! s = [ character(len(s)) :: '1_E', '2_S', '3_E', '14_E', '25_S' ]

    print *, "test(scalar) : ", substr( s(1), 1, 2 )
    print *, "test(array ) : ", substr( s,    1, 2 )

    ind = index( s, '_' )
    comp = substr( s, 1, ind-1 )

    print *
    print *, "string (all)    : ", s
    print *, "string before _ : ", comp
    print *, "string after _  : ", substr( s, ind+1, len(s) )
endprogram

который дает (с гфортраном-7,3)

 test(scalar) : 1_        
 test(array ) : 1_        2_        3_        14        25        

 string (all)    : 1_E       2_S       3_E       14_E      25_S      
 string before _ : 1         2         3         14        25        
 string after _  : E         S         E         E         S     
0 голосов
/ 28 апреля 2018

@ francescalus уже объяснил ошибку, вот мой вклад в вопрос OP, кажется, действительно решает, то есть, как прочитать целые числа из массива строк, таких как

s = (/ '1_E ', '2_S ', '3_E ', '14_E', '25_S' /)

OP хочет сделать это без циклов, а @roygvib указывает нам на использование элементарной функции. Вот моя версия такой функции для чтения целого числа из строки. Это игнорирует любые начальные пробелы, поэтому должно справляться со строками, такими как 12_e. Затем он прекращает сканирование с первого нецифрового символа (поэтому читает 12 из строки, такой как 12_3).

ELEMENTAL INTEGER FUNCTION read_int(str)
  CHARACTER(*), INTENT(in) :: str
  CHARACTER(:), ALLOCATABLE :: instr

  instr = adjustl(str)
  instr = instr(1:VERIFY(instr,'0123456789')-1)
  ! if the string doesn't have a leading digit instr will be empty, return a guard value
  IF(instr=='') instr = '-999'
  READ(instr,*) read_int
END FUNCTION read_int

Я верю, что это достаточно ясно. ОП мог тогда написать

n = read_int(s)
0 голосов
/ 28 апреля 2018

У вас есть пара проблем здесь. Один из которых легко решается (и был в других вопросах: вы можете найти их для более подробной информации).

Линия 1

n = s(1:i-1)

, на который жалуется компилятор, является попыткой сослаться на секцию массива s, а не на массив подстрок элементов массива s. Для доступа к подстрокам массива вам понадобится

n = s(:)(1:i-1)

Однако это связано с вашей второй проблемой. Поскольку компилятор жалуется на доступ к секции массива, i должен быть скалярным. Это также верно для случая доступа к подстрокам массива. Вышеуказанная строка все равно не будет работать.

По сути, если вы хотите получить доступ к подстрокам массива, каждая подстрока должна иметь точно такую ​​же структуру. То есть в s(:)(i:j) оба i и j должны быть целочисленными скалярными выражениями. Это вызвано желанием, чтобы каждый элемент возвращаемого массива был одинаковой длины.

Тогда вам нужно будет использовать цикл.


1 Как однажды прокомментировал High Performance Mark, также есть проблема с самим назначением. Я рассмотрел просто выражение с правой стороны. Даже с поправкой на допустимую подстроку массива выражение все еще является символьным массивом, который не может быть назначен целочисленному скаляру n по желанию.

Если вы хотите буквальный ответ о выборе подстрок, прочитайте, как указано выше. Если вы просто заботитесь о «преобразовании части массива символов в массив целых чисел», тогда другой ответ охватывает все хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...