glob(3f) - [M_strings:COMPARE] compare given string for match to a pattern which may contain globbing wildcard characters (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
References
License
logical function glob(string, pattern )
character(len=*),intent(in) :: string character(len=*),intent(in) :: pattern
glob(3f) compares an (entire) STRING for a match to a PATTERN which may contain basic wildcard "globbing" characters."*" matches any string. "?" matches any single character.
In this version to get a match the entire string must be described by PATTERN. Trailing whitespace is significant, so trim the input string to have trailing whitespace ignored.
Patterns like "b*ba" fail on a string like "babababa" because the first match found is not at the end of the string so baba does not match
To skip over the early matches insert an extra character at the end of the string and pattern that does not occur in the pattern. Typically a NULL is used (char(0)). So searching for b*ba\0 in babababa\0 matches the entire string.
string the input string to be tested for a match to the pattern. pattern the globbing pattern to search for. The following simple globbing options are available
o "?" matching any one character o "*" matching zero or more characters. Do NOT use adjacent asterisks. o spaces are significant and must be matched or trimmed before the comparison. o There is no escape character, so matching strings with a literal question mark and asterisk is problematic.
Example program
program demo_glob implicit none ! This main routine passes a bunch of test strings ! into the above code. In performance comparison mode, ! it does that over and over. Otherwise, it does it just ! once. Either way, it outputs a passed/failed result. ! integer :: nReps logical :: allpassed integer :: i allpassed = .true.Expected outputnReps = 10000 ! Can choose as many repetitions as youre expecting ! in the real world. nReps = 1
do i=1,nReps ! Cases with repeating character sequences. allpassed= test("a*abab", "a*b", .true.) .and. allpassed allpassed= test("ab", "*?", .true.) .and. allpassed allpassed= test("abc", "*?", .true.) .and. allpassed allpassed= test("abcccd", "*ccd", .true.) .and. allpassed allpassed= test("bLah", "bLaH", .false.) .and. allpassed allpassed= test("mississippi", "*sip*", .true.) .and. allpassed allpassed= & & test("xxxx*zzzzzzzzy*f", "xxx*zzy*f", .true.) .and. allpassed allpassed= & & test("xxxx*zzzzzzzzy*f", "xxxx*zzy*fffff", .false.) .and. allpassed allpassed= & & test("mississipissippi", "*issip*ss*", .true.) .and. allpassed allpassed= & & test("xxxxzzzzzzzzyf", "xxxx*zzy*fffff", .false.) .and. allpassed allpassed= & & test("xxxxzzzzzzzzyf", "xxxx*zzy*f", .true.) .and. allpassed allpassed= test("xyxyxyzyxyz", "xy*z*xyz", .true.) .and. allpassed allpassed= test("xyxyxyxyz", "xy*xyz", .true.) .and. allpassed allpassed= test("mississippi", "mi*sip*", .true.) .and. allpassed allpassed= test("ababac", "*abac*", .true.) .and. allpassed allpassed= test("aaazz", "a*zz*", .true.) .and. allpassed allpassed= test("a12b12", "*12*23", .false.) .and. allpassed allpassed= test("a12b12", "a12b", .false.) .and. allpassed allpassed= test("a12b12", "*12*12*", .true.) .and. allpassed
! Additional cases where the * char appears in the tame string. allpassed= test("*", "*", .true.) .and. allpassed allpassed= test("a*r", "a*", .true.) .and. allpassed allpassed= test("a*ar", "a*aar", .false.) .and. allpassed
! More double wildcard scenarios. allpassed= test("XYXYXYZYXYz", "XY*Z*XYz", .true.) .and. allpassed allpassed= test("missisSIPpi", "*SIP*", .true.) .and. allpassed allpassed= test("mississipPI", "*issip*PI", .true.) .and. allpassed allpassed= test("xyxyxyxyz", "xy*xyz", .true.) .and. allpassed allpassed= test("miSsissippi", "mi*sip*", .true.) .and. allpassed allpassed= test("miSsissippi", "mi*Sip*", .false.) .and. allpassed allpassed= test("abAbac", "*Abac*", .true.) .and. allpassed allpassed= test("aAazz", "a*zz*", .true.) .and. allpassed allpassed= test("A12b12", "*12*23", .false.) .and. allpassed allpassed= test("a12B12", "*12*12*", .true.) .and. allpassed allpassed= test("oWn", "*oWn*", .true.) .and. allpassed
! Completely tame (no wildcards) cases. allpassed= test("bLah", "bLah", .true.) .and. allpassed
! Simple mixed wildcard tests suggested by IBMer Marlin Deckert. allpassed= test("a", "*?", .true.) .and. allpassed
! More mixed wildcard tests including coverage for false positives. allpassed= test("a", "??", .false.) .and. allpassed allpassed= test("ab", "?*?", .true.) .and. allpassed allpassed= test("ab", "*?*?*", .true.) .and. allpassed allpassed= test("abc", "?**?*?", .true.) .and. allpassed allpassed= test("abc", "?**?*&?", .false.) .and. allpassed allpassed= test("abcd", "?b*??", .true.) .and. allpassed allpassed= test("abcd", "?a*??", .false.) .and. allpassed allpassed= test("abcd", "?**?c?", .true.) .and. allpassed allpassed= test("abcd", "?**?d?", .false.) .and. allpassed allpassed= test("abcde", "?*b*?*d*?", .true.) .and. allpassed
! Single-character-match cases. allpassed= test("bLah", "bL?h", .true.) .and. allpassed allpassed= test("bLaaa", "bLa?", .false.) .and. allpassed allpassed= test("bLah", "bLa?", .true.) .and. allpassed allpassed= test("bLaH", "?Lah", .false.) .and. allpassed allpassed= test("bLaH", "?LaH", .true.) .and. allpassed
allpassed= test(abcdefghijk , ?b*, .true.) .and. allpassed allpassed= test(abcdefghijk , *c*, .true.) .and. allpassed allpassed= test(abcdefghijk , *c, .false.) .and. allpassed allpassed= test(abcdefghijk , *c*k, .true.) .and. allpassed allpassed= test(LS , ?OW, .false.) .and. allpassed allpassed= test(teztit , tez*t*t, .true.) .and. allpassed ! Two pattern match problems that might pose difficulties allpassed= test(e , *e* , .true.) .and. allpassed allpassed= test(abcde , *e *, .true.) .and. allpassed allpassed= test(bababa , b*ba, .true.) .and. allpassed allpassed= test(baaaaax , b*ax, .true.) .and. allpassed allpassed= test(baaaaa , b*ax, .false.) .and. allpassed allpassed= test(baaaaax , b*a, .false.) .and. allpassed allpassed= test( , b*, .false.) .and. allpassed allpassed= test( , *, .true.) .and. allpassed allpassed= test(b , , .false.) .and. allpassed allpassed= test(3 , ??, .false.) .and. allpassed ! known flaws allpassed= test( , , .true.) .and. allpassed allpassed= test(baaaaa , b*a, .true.) .and. allpassed ! add unused character to work around allpassed= test(//char(0), //char(0), .true.).and.allpassed allpassed= test(baaaaa//char(0),b*a//char(0),.true.).and.allpassed
! Many-wildcard scenarios. allpassed= test(& &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",& &"a*a*a*a*a*a*aa*aaa*a*a*b",& &.true.) .and. allpassed allpassed= test(& &"abababababababababababababababababababaacacacacacacac& &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",& &"*a*b*ba*ca*a*aa*aaa*fa*ga*b*",& &.true.) .and. allpassed allpassed= test(& &"abababababababababababababababababababaacacacacacaca& &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",& &"*a*b*ba*ca*a*x*aaa*fa*ga*b*",& &.false.) .and. allpassed allpassed= test(& &"abababababababababababababababababababaacacacacacacacad& &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",& &"*a*b*ba*ca*aaaa*fa*ga*gggg*b*",& &.false.) .and. allpassed allpassed= test(& &"abababababababababababababababababababaacacacacacacacad& &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",& &"*a*b*ba*ca*aaaa*fa*ga*ggg*b*",& &.true.) .and. allpassed allpassed= test("aaabbaabbaab","*aabbaa*a*",.true.).and.allpassed allpassed= & test("a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",& &"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.) .and. allpassed allpassed= test("aaaaaaaaaaaaaaaaa",& &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.) .and. allpassed allpassed= test("aaaaaaaaaaaaaaaa",& &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .false.) .and. allpassed allpassed= test(& &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",& & "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& &*abc*abc*abc*",& &.false.) .and. allpassed allpassed= test(& &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",& &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",& &.true.) .and. allpassed allpassed= test("abc*abcd*abcd*abc*abcd",& &"abc*abc*abc*abc*abc", .false.) .and. allpassed allpassed= test( "abc*abcd*abcd*abc*abcd*abcd& &*abc*abcd*abc*abc*abcd", & &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",& &.true.) .and. allpassed allpassed= test("abc",& &"********a********b********c********", .true.) .and. allpassed allpassed=& &test("********a********b********c********", "abc",.false.)& & .and.allpassed allpassed= & &test("abc", "********a********b********b********",.false.)& & .and.allpassed allpassed= test("*abc*", "***a*b*c***", .true.) .and. allpassed
! A case-insensitive algorithm test. ! allpassed=test("mississippi", "*issip*PI", .true.) .and. allpassed enddo
if (allpassed)then write(*,(*(g0,1x)))"Passed",nReps else write(*,(a))"Failed" endif contains ! This is a test program for wildcard matching routines. ! It can be used either to test a single routine for correctness, ! or to compare the timings of two (or more) different wildcard ! matching routines. ! function test(tame, wild, bExpectedResult) result(bPassed) use M_strings, only : glob character(len=*) :: tame character(len=*) :: wild logical :: bExpectedResult logical :: bResult logical :: bPassed bResult = .true. ! Well do "&=" cumulative checking. bPassed = .false. ! Assume the worst. write(*,*)repeat(=,79) bResult = glob(tame, wild) ! Call a wildcard matching routine.
! To assist correctness checking, output the two strings in any ! failing scenarios. if (bExpectedResult .eqv. bResult) then bPassed = .true. if(nReps == 1) write(*,*)"Passed match on ",tame," vs. ", wild else if(nReps == 1) write(*,*)"Failed match on ",tame," vs. ", wild endif
end function test end program demo_glob
John S. Urban
The article "Matching Wildcards: An Empirical Way to Tame an Algorithm" in Dr Dobbs Journal, By Kirk J. Krauss, October 07, 2014
Public Domain
Nemo Release 3.1 | glob (3m_strings) | January 10, 2025 |