PP#10~Fortran Tips#5
サブルーチンstrtoimdの作成編の最終回です。これで文字列呼び込みルーチンReadDblArrayが完成します。
前回は読み込んだ文字列の文字数をカウントしましたが、今回は読み込んだ文字数を数値に変換する処理を行います。
繰り返しますが、文字”*”の前段の数値は後段の実数を読み込む回数の事です。念のため。
subroutine strtoimd(Line, Nx, Words, NumValue, IntValue, DblValue) !******************************************************************************** !* * !* Convert the String to Integer and Double * !* * !******************************************************************************** implicit none integer,intent(in):: Nx integer,intent(out):: NumValue, IntValue(Nx) real*8,intent(out):: DblValue(Nx) character,intent(inout)::Line*(*) integer:: NumWord,NumChar(Nx),length, cbegin, cend, count, star, & endPtr, i, j, k character:: Words(Nx)*(*) logical:: digit !================================================================================ ! Function : Convert string to float including the expression like ! : "15*100.0", which is read as double (100.0) by int (15) ! Line : Each line in the input data ! NumWord : Number of words in the Line ! NumChar : Number of characters in each word ! Words : Array of the words comprised of the line ! NumValue : Number of values extracted from the Line ! IntValue : Integer value extracted from the Line ! DblValue : Double value extracted from the Line ! endPtr : Pointer of the remaining word after converting the word ! length : Length of Line ! cbegin : Location of the first character of each word ! cend : Location of the last character of each word ! count : Number of count !================================================================================ !Extract words from Line given !================================================================================ length = len_trim(Line) !Calculate length of the string without space !Global loop to find the "void" character cbegin = 1 cend = 1 count = 0 do while (cbegin <=length) if ( Line(cbegin:cbegin) == '0' .or. Line(cbegin:cbegin) == '1' .or. & Line(cbegin:cbegin) == '2' .or. Line(cbegin:cbegin) == '3' .or. & Line(cbegin:cbegin) == '4' .or. Line(cbegin:cbegin) == '5' .or. & Line(cbegin:cbegin) == '6' .or. Line(cbegin:cbegin) == '7' .or. & Line(cbegin:cbegin) == '8' .or. Line(cbegin:cbegin) == '9' .or. & Line(cbegin:cbegin) == '-' .or. Line(cbegin:cbegin) == '.' ) then count = count + 1 do j=cbegin+1,length+1 !Local loop to find the next "void" character if (Line(j:j) == ' ' .or. Line(j:j) == '\0' .or. Line(j:j) == '\n') then cend = j - 1 exit endif cend = j enddo NumChar(count) = cend - cbegin + 1 do k=1,NumChar(count) Words(count)(k:k) = Line(cbegin+k-1:cbegin+k-1) enddo cbegin = cend endif cbegin = cbegin + 1 enddo NumWord = count !print *, "Numword= ",NumWord, ", Word= ",Words(NumWord) !================================================================================ !Convert words to digit !================================================================================ count = 0 !Count number of values do i=1,NumWord digit = .true. do j=1,NumChar(i) !Check if Words is digit or letter if (.not.( Words(i)(j:j) == '0' .or. Words(i)(j:j) == '1' .or. & Words(i)(j:j) == '2' .or. Words(i)(j:j) == '3' .or. & Words(i)(j:j) == '4' .or. Words(i)(j:j) == '5' .or. & Words(i)(j:j) == '6' .or. Words(i)(j:j) == '7' .or. & Words(i)(j:j) == '8' .or. Words(i)(j:j) == '9' .or. & Words(i)(j:j) == '-' .or. Words(i)(j:j) == '.' .or. & Words(i)(j:j) == '*' ) ) digit = .false. enddo !Convert the string to float if (digit) then !Words contains digit only !Check if string contains '*' and location number star = index( Words(i)(1:NumChar(i)), '*' ) !Convert the string to int and double if (star > 0) then count = count + 1 IntValue(count) = atoi( Words(i)(:star-1)) DblValue(count) = atof( Words(i)(star+1:NumChar(i))) else count = count + 1 IntValue(count) = 1 DblValue(count) = atof( Words(i)(1:NumChar(i))) endif endif NumValue = count !print *,"Words = ",Words(i),", NumValue = ",NumValue,", IntValue = ",IntValue(i),", DblValue = ",DblValue(i),", ChrValue = ",ChrValue(i) enddo !================================================================================ end subroutine
呼び出すルーチンを含めて、これまで作成した一連の関係サブルーチンを下記に纏めておきます。
program call_ReadDblArray !******************************************************************************** !* call_ReadDblArray * !******************************************************************************** implicit none integer,parameter:: fin = 5 integer,parameter:: Nx = 10, LINEMAX = 130 character(len=LINEMAX)::inkey integer:: Inx, ip real*8:: DblArray(Nx) !================================================================================ do call getline(fin, inkey) print '("Key to be input (/ to exit): ", a)', inkey if (inkey == '/') exit Inx = 0; call ReadDblArray(inkey, LINEMAX, Inx, Nx, DblArray) print '("Value to be output:")' do ip=1,Inx print '("DblArray (",i2,") = ",f20.7)', ip, DblArray(ip) enddo enddo print '("Reached end of program")' !================================================================================ stop !================================================================================ contains !================================================================================ integer function atoi(String) !************************************************************************ !* Convert String to Interger Value * !************************************************************************ implicit none character,intent(in):: String*(*) integer:: count, digit !======================================================================== !read(String,'(i10)') atoi !======================================================================== count = 1 atoi = 0 do while (count<=len(trim(String))) if (String(count:count) >= '0' .and. String(count:count) <= '9') then read(String(count:count),*) digit atoi = 10*atoi + digit endif count = count + 1 enddo !print '("atoi ", i10)', atoi !======================================================================== end function real*8 function atof(String) !************************************************************************ !* Convert String to Double Precision Value * !************************************************************************ implicit none character,intent(in):: String*(*) !======================================================================== read(String,*) atof !======================================================================== end function subroutine getline(File, Line) !******************************************************************************** !* Read Data in a Line * !******************************************************************************** implicit none integer,intent(in):: File character,intent(inout)::Line*(*) !================================================================================ read(File, '(a)') Line !================================================================================ end subroutine subroutine ReadDblArray(Line, LineMax, Inx, Nx, DblArray) !******************************************************************************** !* Read the Double Array * !******************************************************************************** implicit none integer,intent(in):: Nx, LineMax integer,intent(inout):: Inx real*8,intent(out):: DblArray(Nx) character,intent(inout)::Line*(*) integer:: NumWord, NumValue, IntValue(Nx), i, j real*8:: DblValue(Nx) character:: Words(Nx)*LineMax !================================================================================ ! Line : Line string given ! LineMax : Max characters in Line ! Inx : Index of the DblArray ! Nx : Number of array of the words comprised of the line ! DblArray : Array to be inputed ! NumWord : Number of words in the Line ! Words : Array of the words comprised of the line ! NumValue : Number of values ! IntValue(Nx): Integer value extracted from the Line ! DblValue(Nx): Double value extracted from the Line !================================================================================ ! Extract IntValue and DblValue from the line string given !================================================================================ call strtoimd(Line, Nx, Words, NumValue, IntValue, DblValue) !================================================================================ ! Input DbleArray given !================================================================================ do i=1,NumValue do j=1,IntValue(i) Inx = Inx + 1 DblArray(Inx) = DblValue(i) enddo enddo !================================================================================ end subroutine subroutine strtoimd(Line, Nx, Words, NumValue, IntValue, DblValue) !******************************************************************************** !* * !* Convert the String to Integer and Double * !* * !******************************************************************************** ................. !================================================================================ end subroutine end program
事例として二つの文字列を入力させた結果はこんな感じ。
如何でしたか?
因みに、strtoimdとはString To Integer and Doubleを示します。うろ覚えですが。
以上