2015-05-02 4 views
0

Я хотел бы прочитать файл данных с программой Fortran, где каждая строка представляет собой список целых чисел.Чтение файла списков целых чисел в Fortran

Каждая строка имеет переменное число целых чисел, разделенных данным символом (пробел, запятая ...).

Пример ввода:

1,7,3,2 
2,8 
12,44,13,11 

У меня есть решение разделить строки, которые я нахожу довольно запутанным:

module split 
    implicit none 
contains 
    function string_to_integers(str, sep) result(a) 
     integer, allocatable :: a(:) 
     integer :: i, j, k, n, m, p, r 
     character(*) :: str 
     character :: sep, c 
     character(:), allocatable :: tmp 

     !First pass: find number of items (m), and maximum length of an item (r) 
     n = len_trim(str) 
     m = 1 
     j = 0 
     r = 0 
     do i = 1, n 
      if(str(i:i) == sep) then 
       m = m + 1 
       r = max(r, j) 
       j = 0 
      else 
       j = j + 1 
      end if 
     end do 
     r = max(r, j) 

     allocate(a(m)) 
     allocate(character(r) :: tmp) 

     !Second pass: copy each item into temporary string (tmp), 
     !read an integer from tmp, and write this integer in the output array (a) 
     tmp(1:r) = " " 
     j = 0 
     k = 0 
     do i = 1, n 
      c = str(i:i) 
      if(c == sep) then 
       k = k + 1 
       read(tmp, *) p 
       a(k) = p 
       tmp(1:r) = " " 
       j = 0 
      else 
       j = j + 1 
       tmp(j:j) = c 
      end if 
     end do 
     k = k + 1 
     read(tmp, *) p 
     a(k) = p 
     deallocate(tmp) 
    end function 
end module 

Мой вопрос:

  • Есть более простой способ сделать это в Fortran? Я имею в виду, прочитав список значений, где количество прочитанных значений неизвестно. Вышеприведенный код выглядит неудобно, и файловый ввод-вывод не выглядит легким в Fortran.

  • Кроме того, основная программа должна читать строки с неизвестной и неограниченной длиной. Я могу читать строки, если предположить, что они имеют одинаковую длину (см. Ниже), но я не знаю, как читать неограниченные строки. Полагаю, для этого нужны потоковые функции Fortran 2003, но я не знаю, как это написать.

Вот текущая программа:

program read_data 
    use split 
    implicit none 
    integer :: q 
    integer, allocatable :: a(:) 
    character(80) :: line 
    open(unit=10, file="input.txt", action="read", status="old", form="formatted") 
    do 
     read(10, "(A80)", iostat=q) line 
     if(q /= 0) exit 
     if(line(1:1) /= "#") then 
      a = string_to_integers(line, ",") 
      print *, ubound(a), a 
     end if 
    end do 
    close(10) 
end program 

Комментарий к вопросу: как правило, я хотел бы сделать это в Python, например, преобразование строки будет столь же просто, как a = [int(x) for x in line.split(",")] и чтение файла также почти тривиальная задача. И я бы сделал «реальный» компьютерный материал с помощью Fortran DLL. Тем не менее, я бы хотел улучшить свои навыки Fortran для ввода/вывода файлов.

ответ

1

Я не утверждаю, что это кратчайший возможный, но он намного короче, чем ваш. И как только вы это сделаете, вы можете повторно использовать его. Я не полностью согласен с этими утверждениями в том, как Fotran плохо разбирается в обработке строк, я делаю токенизацию, рекурсивный синтаксический анализ спуска и подобные вещи просто отлично в Fortran, хотя на других языках с более богатыми библиотеками это проще. Иногда вы также можете использовать библиотеки, написанные на других языках (особенно C и C++) в Fortran.

Если вы всегда используете запятую, вы можете удалить замену запятой и тем самым сократить ее еще больше.

function string_to_integers(str, sep) result(a) 
    integer, allocatable :: a(:) 
    character(*) :: str 
    character :: sep 
    integer :: i, n_sep 

    n_sep = 0 
    do i = 1, len(str) 
     if (str(i:i)==sep) then 
     n_sep = n_sep + 1 
     str(i:i) = ',' 
     end if 
    end do 
    allocate(a(n_sep+1)) 
    read(str,*) a 
end function 

Потенциал сокращения: просмотр str как массив символов, используя equivalence или transfer и использовать count() внутри allocate, чтобы получить размер a.

+0

Спасибо! Я не знал этого использования запятой для ввода массива. Что касается претензий к Fortran и обработке строк, возможно, я склонен, так как я изучил Python задолго до того, как узнал Fortran: для строк и ввода-вывода это было шоком :) Из-за этого я удалил свой комментарий, поскольку он, вероятно, несправедлив. Тем не менее, у меня все еще создается впечатление, что в Fortran у вас есть что делать самостоятельно, а синтаксис - не очень дружелюбный. –

0

Мой ответ, вероятно, слишком упрощен для ваших целей, но я провел много времени, недавно прочитав в странных текстовых файлах чисел. Моя самая большая проблема заключается в том, чтобы найти, где они начинаются (не сложно в вашем случае), тогда мой лучший друг - это список, на котором вы читаете.

read(unit=10,fmt=*) a 

будет считывать все данные в вектор «a», заключенную сделку. С помощью этого метода вы не узнаете, из какой строки поступает какая-то часть данных. Если вы хотите выделить его, вы можете прочитать файл один раз и вычислить некоторый алгоритм, чтобы сделать массив больше, чем он должен быть, например, можно подсчитать количество строк, и вы знаете максимальное количество данных в строке (скажем, 21).

status = 0 
    do while (status == 0) 
     line_counter = line_counter + 1 
     read(unit=10,, iostat=status, fmt=*) 
    end do 

allocate(a(counter*21)) 

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

Другой подход, вытекающие из другого предложения является первым сосчитать запятые затем сделать чтение, где цикл контролируется

do j = 1, line_counter   ! You determined this on your first read 
    read(unit=11,fmt=*) a(j,:) ! a is now a 2 dimensional array (line_counter, maxNumberPerLine) 
           ! You have a separate vector numberOfCommas(j) from before 
end do 

И теперь вы можете делать все, что вы хотите с этими массивами, потому что вы знаете все данные, из которых она исходила, и сколько данных было в каждой строке.

Смежные вопросы