Извлечь подстроку из строкового массива Фортрана
Как извлечь подстроку из массива строк Фортрана? Например
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 ответа
В случае, когда следует избегать цикла и нет других (простых) методов, может быть полезно определить элементарную функцию подстроки и применить ее к массиву строк. Например,
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
который дает (с gfortran-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
У вас есть пара проблем здесь. Один из которых легко решается (и был в других вопросах: вы можете найти их для более подробной информации).
Линия1
n = s(1:i-1)
о чем жалуется компилятор - это попытка сослаться на часть массива s
, а не массив подстрок элементов массива s
, Для доступа к подстрокам массива вам понадобится
n = s(:)(1:i-1)
Однако это связано с вашей второй проблемой. Поскольку компилятор жалуется на доступ к разделу массива, i
должен быть скаляр. Это также верно для случая доступа к подстрокам массива. Вышеуказанная строка все равно не будет работать.
По сути, если вы хотите получить доступ к подстрокам массива, каждая подстрока должна иметь точно такую же структуру. То есть в s(:)(i:j)
и то и другое i
а также j
должны быть скалярными целочисленными выражениями. Это вызвано желанием, чтобы каждый элемент возвращаемого массива был одинаковой длины.
Тогда вам нужно будет использовать цикл.
1 Как однажды прокомментировал High Performance Mark, есть проблема с самим назначением. Я рассмотрел просто выражение с правой стороны. Даже исправленное для правильной подстроки массива, выражение все еще является массивом символов, который не может быть назначен на целочисленный скаляр n
по желанию.
Если вы хотите получить буквальный ответ о выборе подстрок, прочитайте, как указано выше. Если вы просто заботитесь о "преобразовании части массива символов в массив целых чисел", тогда другой ответ хорошо охватывает все.
@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)