split_chunked Subroutine

private pure subroutine split_chunked(self, tokens, chunks, sep)

Arguments

TypeIntentOptionalAttributesName
class(string), intent(in) :: self
type(string), intent(out), allocatable:: tokens(:)
integer, intent(in) :: chunks
character(kind=CK,len=*), intent(in), optional :: sep

Contents

Source Code


Source Code

   pure subroutine split_chunked(self, tokens, chunks, sep)
   !< Return a list of substring in the string, using sep as the delimiter string, chunked (memory-efficient) algorithm.
   !<
   !< @note Multiple subsequent separators are collapsed to one occurrence.
   !<
   !< @note The split is performed in chunks of `#chunks` to avoid excessive memory consumption.
   !<
   !<```fortran
   !< type(string)              :: astring
   !< type(string), allocatable :: strings(:)
   !< logical                   :: test_passed(1)
   !< astring = '-1-2-3-4-5-6-7-8-'
   !< call astring%split_chunked(tokens=strings, sep='-', chunks=3)
   !< test_passed(1) = (strings(1)//''=='1'.and.strings(2)//''=='2'.and.strings(3)//''=='3'.and.strings(4)//''=='4'.and. &
   !<                   strings(5)//''=='5'.and.strings(6)//''=='6'.and.strings(7)//''=='7'.and.strings(8)//''=='8')
   !< print '(L1)', all(test_passed)
   !<```
   !=> T <<<
   class(string),             intent(in)           :: self      !< The string.
   type(string), allocatable, intent(out)          :: tokens(:) !< Tokens substring.
   integer,                   intent(in)           :: chunks    !< Number of chunks.
   character(kind=CK, len=*), intent(in), optional :: sep       !< Separator.
   character(kind=CK, len=:), allocatable          :: sep_      !< Separator, default value.
   integer                                         :: Nt        !< Number of actual tokens.
   integer                                         :: t         !< Counter.
   logical                                         :: isok

   if (allocated(self%raw)) then
     sep_ = SPACE ; if (present(sep)) sep_ = sep

     Nt = self%count(sep_)
     if (self%start_with(prefix=sep_)) Nt = Nt - 1
     if (self%end_with(suffix=sep_)) Nt = Nt - 1
     t = 0
     call self%split(tokens=tokens, sep=sep_, max_tokens=chunks)
     do
       t = size(tokens, dim=1)
       if (t > Nt) exit
       call split_last_token(tokens=tokens, max_tokens=chunks,isok=isok)
       if(isok)then
       else
            exit
       endif
     enddo

     t = size(tokens, dim=1)
     if (tokens(t)%count(sep_) > 0) then
        call split_last_token(tokens=tokens,isok=isok)
     endif
   endif

   contains
      pure subroutine split_last_token(tokens, max_tokens,isok)
      !< Split last token.
      type(string), allocatable, intent(inout)        :: tokens(:)      !< Tokens substring.
      integer,                   intent(in), optional :: max_tokens     !< Max tokens returned.
      type(string), allocatable                       :: tokens_(:)     !< Temporary tokens.
      type(string), allocatable                       :: tokens_swap(:) !< Swap tokens.
      integer                                         :: Nt_            !< Number of last created tokens.
      logical,intent(out)                             :: isok

      isok=.true.
      call tokens(t)%split(tokens=tokens_, sep=sep_, max_tokens=max_tokens)
      if (allocated(tokens_)) then
        Nt_ = size(tokens_, dim=1)
        if (Nt_ >= 1) then
          allocate(tokens_swap(1:t-1+Nt_))
          tokens_swap(1:t-1) = tokens(1:t-1)
          tokens_swap(t:)    = tokens_(:)
          call move_alloc(from=tokens_swap, to=tokens)
        endif
        if (Nt_ == 1) then
            isok=.false.
        end if
        deallocate(tokens_)
      endif
      endsubroutine split_last_token
   endsubroutine split_chunked