unquote Function

public function unquote(quoted_str, esc) result(unquoted_str)

NAME

 unquote(3f) - [M_strings:QUOTES] remove quotes from string as if
 read with list-directed input
 (LICENSE:PD)

SYNOPSIS

function unquote(quoted_str,esc) result (unquoted_str)

character(len=*),intent(in)          :: quoted_str
character(len=1),optional,intent(in) :: esc
character(len=:),allocatable         :: unquoted_str

DESCRIPTION

Remove quotes from a CHARACTER variable as if it was read using
list-directed input. This is particularly useful for processing
tokens read from input such as CSV files.

Fortran can now read using list-directed input from an internal file,
which should handle quoted strings, but list-directed input does not
support escape characters, which UNQUOTE(3f) does.

OPTIONS

quoted_str  input string to remove quotes from, using the rules of
            list-directed input (two adjacent quotes inside a quoted
            region are replaced by a single quote, a single quote or
            double quote is selected as the delimiter based on which
            is encountered first going from left to right, ...)
esc         optional character used to protect the next quote
            character from being processed as a quote, but simply as
            a plain character.

RESULT

unquoted_str  The output string, which is based on removing quotes
              from quoted_str.

EXAMPLE

Sample program:

program demo_unquote
   use M_strings, only : unquote
   implicit none
   character(len=128)           :: quoted_str
   character(len=:),allocatable :: unquoted_str
   character(len=1),parameter   :: esc='\'
   character(len=1024)          :: msg
   integer                      :: ios
   character(len=1024)          :: dummy
   do
      write(*,'(a)',advance='no')'Enter test string:'
      read(*,'(a)',iostat=ios,iomsg=msg)quoted_str
      if(ios /= 0)then
         write(*,*)trim(msg)
         exit
      endif

      ! the original string
      write(*,'(a)')'QUOTED       ['//trim(quoted_str)//']'

      ! the string processed by unquote(3f)
      unquoted_str=unquote(trim(quoted_str),esc)
      write(*,'(a)')'UNQUOTED     ['//unquoted_str//']'

      ! read the string list-directed to compare the results
      read(quoted_str,*,iostat=ios,iomsg=msg)dummy
      if(ios /= 0)then
         write(*,*)trim(msg)
      else
         write(*,'(a)')'LIST DIRECTED['//trim(dummy)//']'
      endif
   enddo
end program demo_unquote

AUTHOR

John S. Urban

LICENSE

Public Domain

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: quoted_str
character(len=1), intent(in), optional :: esc

Return Value character(len=:), allocatable


Contents

Source Code


Source Code

function unquote(quoted_str,esc) result (unquoted_str)
character(len=*),intent(in)          :: quoted_str              ! the string to be unquoted
character(len=1),optional,intent(in) :: esc                     ! escape character
character(len=:),allocatable         :: unquoted_str
integer                              :: inlen
character(len=1),parameter           :: single_quote = "'"
character(len=1),parameter           :: double_quote = '"'
integer                              :: quote                   ! whichever quote is to be used
integer                              :: before
integer                              :: current
integer                              :: iesc
integer                              :: iput
integer                              :: i
logical                              :: inside
!-----------------------------------------------------------------------------------------------------------------------------------
   if(present(esc))then                           ! select escape character as specified character or special value meaning not set
      iesc=iachar(esc)                            ! allow for an escape character
   else
      iesc=-1                                     ! set to value that matches no character
   endif
!-----------------------------------------------------------------------------------------------------------------------------------
   inlen=len(quoted_str)                          ! find length of input string
   allocate(character(len=inlen) :: unquoted_str) ! initially make output string length of input string
!-----------------------------------------------------------------------------------------------------------------------------------
   if(inlen >= 1)then                             ! double_quote is the default quote unless the first character is single_quote
      if(quoted_str(1:1) == single_quote)then
         quote=iachar(single_quote)
      else
         quote=iachar(double_quote)
      endif
   else
      quote=iachar(double_quote)
   endif
!-----------------------------------------------------------------------------------------------------------------------------------
   before=-2                                      ! initially set previous character to impossible value
   unquoted_str(:)=''                             ! initialize output string to null string
   iput=1
   inside=.false.
   STEPTHROUGH: do i=1,inlen
      current=iachar(quoted_str(i:i))
      if(before == iesc)then                      ! if previous character was escape use current character unconditionally
           iput=iput-1                            ! backup
           unquoted_str(iput:iput)=char(current)
           iput=iput+1
           before=-2                              ! this could be second esc or quote
      elseif(current == quote)then                ! if current is a quote it depends on whether previous character was a quote
         if(before == quote)then
           unquoted_str(iput:iput)=char(quote)    ! this is second quote so retain it
           iput=iput+1
           before=-2
         elseif(.not.inside.and.before /= iesc)then
            inside=.true.
         else                                     ! this is first quote so ignore it except remember it in case next is a quote
            before=current
         endif
      else
         unquoted_str(iput:iput)=char(current)
         iput=iput+1
         before=current
      endif
   enddo STEPTHROUGH
!-----------------------------------------------------------------------------------------------------------------------------------
   unquoted_str=unquoted_str(:iput-1)
!-----------------------------------------------------------------------------------------------------------------------------------
end function unquote