• Globmatch module from FLIBS

    From PrestonMag@21:1/5 to All on Wed Aug 17 15:10:49 2022
    I have an old version of the source code for FLIBS. I have been using the globmatching module from the strings group. Tracking down an error it seems to me that the string_match function always returns false if the last character in the pattern is a "?"
    wildcard. Is this a known fault and does anyone know a solution please?

    My test version allows a user defined 5 character pattern to be checked against the 5 character string "ALERT"

    A pattern of "ALER?" returns false when it should return true.

    I am using Gfortran version 11.2 running under Code::blocks.

    My test code is
    program TestGlobMatch

    implicit none


    character*5 String/'ALERT'/
    character*5 pattern/'ALER?'/
    character*1 c1
    logical mymatch, string_match

    print *, "Hello TestGlobMatch World!"

    write(*,fmt="(a)") ' '
    write(*.fmt="(A,$)") 'Enter 5 charactacter pattern: '
    read(*,fmt="(a)") pattern

    write(*,fmt="(5A)") "String = <",string,">, Pattern = <",pattern,">"
    ! write(*,fmt="(3A)") "Pattern = <",pattern,">"

    mymatch = string_match(String,pattern)
    write(*,fmt="(A,L,A)") "Match returned as <",mymatch,">"

    write(*,fmt="(A,$)") "Hit enter "
    read(*,fmt="(A)") c1

    end program
    recursive function string_match( string, pattern ) result(match)
    implicit none

    character(len=1), parameter :: backslash = '\'
    character(len=1), parameter :: star = '*'
    character(len=1), parameter :: question = '?'
    character(len=*), intent(in) :: string
    character(len=*), intent(in) :: pattern
    logical :: match

    character(len=len(pattern)) :: literal
    integer :: ptrim
    integer :: p
    integer :: k
    integer :: ll
    integer :: method
    integer :: start
    integer :: strim

    match = .false.
    method = 0
    ptrim = len_trim( pattern )
    strim = len_trim( string )
    p = 1
    ll = 0
    start = 1

    !
    ! Split off a piece of the pattern
    !
    do while ( p <= ptrim )
    select case ( pattern(p:p) )
    case( star )
    if ( ll .ne. 0 ) exit
    method = 1
    case( question )
    if ( ll .ne. 0 ) exit
    method = 2
    start = start + 1
    case( backslash )
    p = p + 1
    ll = ll + 1
    literal(ll:ll) = pattern(p:p)
    case default
    ll = ll + 1
    literal(ll:ll) = pattern(p:p)
    end select

    p = p + 1
    enddo

    !
    ! Now look for the literal string (if any!)
    !
    if ( method == 0 ) then
    !
    ! We are at the end of the pattern, and of the string?
    !
    if ( strim == 0 .and. ptrim == 0 ) then
    match = .true.
    else
    !
    ! The string matches a literal part?
    !
    if ( ll > 0 ) then
    if ( string(start:min(strim,start+ll-1)) == literal(1:ll) ) then
    start = start + ll
    match = string_match( string(start:), pattern(p:) )
    endif
    endif
    endif
    endif

    if ( method == 1 ) then
    !
    ! Scan the whole of the remaining string ...
    !
    if ( ll == 0 ) then
    match = .true.
    else
    do while ( start <= strim )
    k = index( string(start:), literal(1:ll) )
    if ( k > 0 ) then
    start = start + k + ll - 1
    match = string_match( string(start:), pattern(p:) )
    if ( match ) then
    exit
    endif
    endif

    start = start + 1
    enddo
    endif
    endif

    if ( method == 2 .and. ll > 0 ) then
    !
    ! Scan the whole of the remaining string ...
    !
    if ( string(start:min(strim,start+ll-1)) == literal(1:ll) ) then
    match = string_match( string(start+ll:), pattern(p:) )
    endif
    endif
    return
    end function string_match

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Wed Aug 17 15:52:35 2022
    (snip)

    if ( method == 2 .and. ll > 0 ) then
    !
    ! Scan the whole of the remaining string ...
    !
    if ( string(start:min(strim,start+ll-1)) == literal(1:ll) ) then
    match = string_match( string(start+ll:), pattern(p:) )
    endif
    endif
    return
    end function string_match

    If method==2 and ll==0 then you should return .true.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Wed Aug 17 17:53:39 2022
    The glob() procedure in

    https://github.com/urbanjost/M_strings

    is similar and there is a relatively extensive test program included. It is PD and I think (not sure) the FLIB procedure might be GPL licensed, if that makes a difference.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Wed Aug 17 18:30:40 2022
    https://fortranwiki.org/fortran/show/match_wild

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From PrestonMag@21:1/5 to John on Thu Aug 18 03:14:35 2022
    On Thursday, 18 August 2022 at 02:30:42 UTC+1, John wrote:
    https://fortranwiki.org/fortran/show/match_wild

    Thank-you, everyone. I've tried the match_wild function in my test code and it works perfectly. I'll now incorporate it in my main software but don't expect and problems

    Thank-you again

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sat Aug 20 00:28:29 2022
    Since I mentioned the other routines, I wanted to post the results of some tests of the listed procedures.

    There is a test program of the three
    procedures that shows that if a NULL character is assumed otherwise not
    used in the string and pattern and is appended that the glob() procedure
    passes all tests, and the string_match() routine passes all tests except
    for an issue with patterns composed completely of wildcard characters,
    but that the match_wild procedure (surprisingly, as it has been available
    from the Fortran Wiki for a long time as well as other sites) seems to
    fail on a number of cases.

    The string_match() procedure was altered to prevent undersubscripting
    and oversubscripting but was not changed otherwise, although the fix
    described above may reduce the failures when the null is not added. Have
    not had time to try it yet.

    At some point I want to add [a-b] character ranges and escaping if it does not have it
    to one
    of these (probably glob()) and/or make an interface to the C procedure fnmatch() if it is available on most platforms, so I wanted to look at
    the currently available routines anyway; but since you mentioned you
    used match_wild() I wanted to mention the preliminary results showed
    some failures and that if appending a null is acceptable string_match()
    works pretty well after all almost as-is except for the outlier with the
    '*?' pattern so far.

    The test program and procedures will be in

    wget http://www.urbanjost.altervista.org/REMOVE/match.tgz

    for at least a few months with the test program and module (set up for
    fpm(1) but pretty easy to just compile) for anyone interested. It seemed
    a bit long to post. I do not see anything I did obviously wrong when
    using string_match().

    I got the same results with ifort, gfortran, and nvfortran compilers
    tested so far.

    Note also that there is a BRE (Basic Regular Expression) routine
    in the GPF package at https://github.com/urbanjost.

    The significant output from the test is summarized below:

    > >>>>>>>>>>>>>> METHOD 1: glob with //char(0)
    > Passed
    > >>>>>>>>>>>>>> METHOD 2: string_match with //char(0)
    > Failed match on ab vs. *?
    > Failed match on abc vs. *?
    > Failed
    > >>>>>>>>>>>>>> METHOD 3: match_wild with //char(0)
    > Failed match on abcccd vs. *ccd
    > Failed match on mississippi vs. *sip*
    > Failed match on mississipissippi vs. *issip*ss*
    > Failed match on mississippi vs. mi*sip*
    > Failed match on ababac vs. *abac*
    > Failed match on mississipPI vs. *issip*PI
    > Failed match on bababa vs. b*ba
    > Failed match on aaabbaabbaab vs. *aabbaa*a*
    > Failed
    > >>>>>>>>>>>>>> METHOD 4: glob
    > Failed match on baaaaa vs. b*a
    > Failed match on vs.
    > Failed
    > >>>>>>>>>>>>>> METHOD 5: string_match
    > Failed match on ab vs. *?
    > Failed match on abc vs. *?
    > Failed match on a vs. *?
    > Failed match on ab vs. ?*?
    > Failed match on abc vs. ?**?*?
    > Failed match on abcd vs. ?b*??
    > Failed match on abcd vs. ?**?c?
    > Failed match on abcde vs. ?*b*?*d*?
    > Failed match on bLah vs. bLa?
    > Failed match on bababa vs. b*ba
    > Failed
    > >>>>>>>>>>>>>> METHOD 6: match_wild
    > Failed match on a*abab vs. a*b
    > Failed match on abcccd vs. *ccd
    > Failed match on mississippi vs. *sip*
    > Failed match on mississipissippi vs. *issip*ss*
    > Failed match on mississippi vs. mi*sip*
    > Failed match on ababac vs. *abac*
    > Failed match on mississipPI vs. *issip*PI
    > Failed match on ab vs. *?*?*
    > Failed match on abc vs. ?**?*?
    > Failed match on abcde vs. ?*b*?*d*?
    > Failed match on abcde vs. *e *
    > Failed match on baaaaa vs. b*a
    > Failed match on bababa vs. b*ba
    > Failed match on b vs.
    > Failed match on aaabbaabbaab vs. *aabbaa*a*
    > Failed match on abc vs. ********a********b********c********
    > Failed

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)