getvals Subroutine

public subroutine getvals(line, values, icount, ierr)

NAME

getvals(3f) - [M_strings:TYPE] read arbitrary number of REAL values
from a character variable up to size of VALUES() array
(LICENSE:PD)

SYNOPSIS

subroutine getvals(line,values,icount,ierr)

 character(len=*),intent(in)  :: line
 class(*),intent(out)         :: values(:)
 integer,intent(out)          :: icount
 integer,intent(out),optional :: ierr

DESCRIPTION

GETVALS(3f) reads a relatively arbitrary number of numeric values from a character variable into a REAL array using list-directed input.

NOTE: In this version null values are skipped instead of meaning to leave that value unchanged

    1,,,,,,,2 / reads VALUES=[1.0,2.0]

Per list-directed rules when reading values, allowed delimiters are comma, semi-colon and space.

the slash separator can be used to add inline comments.

    10.1, 20.43e-1 ; 11 / THIS IS TREATED AS A COMMENT

Repeat syntax can be used up to the size of the output array. These are equivalent input lines:

    4*10.0
    10.0, 10.0, 10.0, 10.0

OPTIONS

LINE A character variable containing the characters representing a list of numbers

RETURNS

VALUES() array holding numbers read from string. May be of type INTEGER, REAL, DOUBLEPRECISION, or CHARACTER. If CHARACTER the strings are returned as simple words instead of numeric values. ICOUNT number of defined numbers in VALUES(). If ICOUNT reaches the size of the VALUES() array parsing stops. IERR zero if no error occurred in reading numbers. Optional. If not present and an error occurs the program is terminated.

EXAMPLES

Sample program:

   program demo_getvals
   use M_strings, only: getvals
   implicit none
   integer,parameter  :: longest_line=256
   character(len=longest_line) :: line
   real               :: values(longest_line/2+1)
   integer            :: ios,icount,ierr
   INFINITE: do
      read(*,'(a)',iostat=ios) line
      if(ios /= 0)exit INFINITE
      call getvals(line,values,icount,ierr)
      write(*,'(4(g0,1x))')'VALUES=',values(:icount)
   enddo INFINITE
   end program demo_getvals

Sample input lines

    10,20 30.4
    1 2 3
    1

    3 4*2.5 8
    32.3333 / comment 1
    30e3;300,    30.0, 3
    even 1 like this! 10
    11,,,,22,,,,33

Expected output:

 VALUES=   10.0000000       20.0000000       30.3999996
 VALUES=   1.00000000       2.00000000       3.00000000
 VALUES=   1.00000000
 VALUES=
 VALUES=   3.00000000       2.50000000       2.50000000
 2.50000000       2.50000000       8.00000000
 VALUES=   32.3333015
 VALUES=   30000.0000       300.000000       30.0000000
 3.00000000
 *getvals* WARNING:[even] is not a number
 *getvals* WARNING:[like] is not a number
 *getvals* WARNING:[this!] is not a number
 VALUES=   1.00000000       10.0000000
 VALUES=   11.0000000       22.0000000       33.0000000

AUTHOR

John S. Urban

LICENSE

Public Domain

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: line
class(*), intent(out) :: values(:)
integer, intent(out) :: icount
integer, intent(out), optional :: ierr

Contents

Source Code


Source Code

subroutine getvals(line,values,icount,ierr)

! ident_62="@(#) M_strings getvals(3f) read arbitrary number of values from a character variable"

! JSU 20170831

character(len=*),intent(in)  :: line
class(*),intent(out)         :: values(:)
integer,intent(out)          :: icount
integer,intent(out),optional :: ierr

character(len=:),allocatable :: buffer
character(len=len(line))     :: words(size(values))
integer                      :: ios, i, ierr_local,isize

   isize=0
   select type(values)
   type is (integer);          isize=size(values)
   type is (real);             isize=size(values)
   type is (doubleprecision);  isize=size(values)
   type is (character(len=*)); isize=size(values)
   end select

   ierr_local=0

   words=' '                            ! make sure words() is initialized to null+blanks
   buffer=trim(unquote(line))//"/"      ! add a slash to the end so how the read behaves with missing values is clearly defined
   read(buffer,*,iostat=ios) words      ! undelimited strings are read into an array
   icount=0
   do i=1,isize                         ! loop thru array and convert non-blank words to numbers
      if(words(i) == ' ')cycle

      select type(values)
      type is (integer);          read(words(i),*,iostat=ios)values(icount+1)
      type is (real);             read(words(i),*,iostat=ios)values(icount+1)
      type is (doubleprecision);  read(words(i),*,iostat=ios)values(icount+1)
      type is (character(len=*)); values(icount+1)=words(i)
      end select

      if(ios == 0)then
         icount=icount+1
      else
         ierr_local=ios
         write(ERROR_UNIT,*)'*getvals* WARNING:['//trim(words(i))//'] is not a number of specified type'
      endif
   enddo

   if(present(ierr))then
      ierr=ierr_local
   elseif(ierr_local /= 0)then        ! error occurred and not returning error to main program to print message and stop program
      write(ERROR_UNIT,*)'*getval* error reading line ['//trim(line)//']'
      stop 2
   endif

end subroutine getvals