Project 2

Some languages, such as Python, can split a string on a specified delimiter character and return a list of strings. The delimiter is dropped. Write a program that can accomplish this.

This should be a function, but we have not yet covered subprograms, so you may write a monolithic program. If you wish to look ahead, write this as a function.

Ideally we would use varying-length strings, but for them to be really useful for this project, we would need an allocatable array of varying-length strings, which requires a derived type or use of more advanced intrinsics.

Print the result in Python format,

[sub1,sub2,sub3]
Sample solution

program splitter

    character(len=256)              :: input, temp
    character(len=80), dimension(:), allocatable :: output
    character                       :: delimiter, ch
    integer                         :: i, ndelims, nchars, chunk

    input="Sample ;string ;for ; this; project \n"
    delimiter=';'
    temp=""

    !First count how many delimiters

    do i=1,len(input)
        if (input(i:i)==delimiter) then
            ndelims=ndelims+1
        endif
    enddo

    !Allocate the array
    allocate(output(ndelims+1))

    chunk=1
    nchars=0
    do i=1,len(input)
        ch=input(i:i)
        nchars=nchars+1
        if (ch==delimiter) then
            output(chunk)=trim(temp)
            temp=""
            nchars=0
            chunk=chunk+1
        endif
        temp(nchars:nchars)=ch
    enddo
    output(chunk)=trim(temp)

    write(*,'(a)',advance="no") "["
    do i=1,size(output)-1
        write(*,'(a,a)',advance="no") trim(output(i)),","
    enddo
    write(*,*) trim(output(size(output))),"]"

end program

   

Bonus Project

A consultant was given a program that has code to generate a format string dynamically. In particular, it can print items that might be arrays, with the repeat value generated automatically.
For example, given n1=5, n2=1, n3=3 and a pattern ‘(#e15.8,#i5,#f8.2)’ the result would be ‘(5e15.8,1i5,3f8.2)’. However, it didn’t work if any of the n1, n2, n3 variables were two digits. The algorithm was convoluted and hard to understand. It did work for two digits if the programmer used two hash marks, e.g. ##e15.8, but that required hand-editing the several files with output routines to find every place she wanted to write out more than 9 array elements. The author of the original code didn’t use any character or string functions other than substrings. This would surely be implemented more generally with better use of strings. Your task is to come up with a way to do this. If you have time, come up with a way to handle a 0 (i.e. skip printing). Test your program carefully.

Hints. You do not need to use a variable-length string, but if not, be sure to declare a generously-sized set of strings (32 or even 64 characters, for example). If using a fixed-length string, remember that you will need to remove blank space. Test your program for n1=10, n2=2, n3=3. Try another pattern like ‘(#es12.4,#i2,#f15.7,#i4)’. Suggestion: use an allocatable array for the coefficients (both numerical and character). Use array size to make sure they match.

Sample solution

program formatter

real, dimension(10)     :: A
real, dimension(3)      :: B
integer                 :: i,m,dlen
character(len=32)       :: formatstr, pattern, chunk
character(len=1)        :: delimiter
integer,           allocatable, dimension(:) :: nvars
character(len=4),  allocatable, dimension(:) :: cn

   A=[(real(i**2),i=1,10)]
   B=[(real(j/2.),j=20,26,3)]
   m=11

   delimiter='#'
   pattern='(#e15.3,#i6,#f15.7)'

   numchars=len(pattern)
   dlen=len(delimiter)

   allocate(nvars(3))
   nvars(1)=size(A)
   nvars(2)=2
   nvars(3)=size(B)

   allocate(cn(size(nvars)))
   do i=1,len(cn)
      write(cn(i),'(i4)') nvars(i)
   enddo

   formatstr=''
   chunk=''
   n=1
   do 
      m=index(pattern,delimiter)
      if ( m==0 .or. len(pattern)==0 ) then
         exit
      else
         chunk=pattern(:m-1)
         pattern=pattern(m+dlen:)
         if (nvars(n) /= 0) then 
            formatstr=trim(adjustl(formatstr))//trim(adjustl(chunk))//&
                      trim(adjustl(cn(n)))
         else
            continue
         endif
         n=n+1
      endif
   enddo
   formatstr=trim(adjustl(formatstr))//trim(adjustl(pattern(:)))
   deallocate(nvars,cn)
   print *, formatstr

end program

Previous
Next