VERIFY(3f) - [M_unicode:SEARCH] Position of a character in a string of characters that does not appear in a given set of characters. (LICENSE:MIT)
Synopsis
Characteristics
Description
Options
Result
Examples
See Also
Author
License
result = verify(string, set [,back] [,kind] )
elemental integer function verify(string,set,back,KIND)type(unicode_type),intent(in) :: string
type(unicode_type),intent(in) :: set or character(len=*),intent(in) :: set
logical,intent(in),optional :: back
o STRING must be of type string o SET must be of type string or character. o BACK shall be of type logical. o A default integer kind is returned.
VERIFY(3) verifies that all the characters in STRING belong to the set of characters in SET by identifying the position of the first character in the string that is not in the set.This makes it easy to verify strings are all uppercase or lowercase, follow a basic syntax, only contain printable characters, and many of the conditions tested for with the C routines ISALNUM(3c), ISALPHA(3c), ISASCII(3c), ISBLANK(3c), ISCNTRL(3c), ISDIGIT(3c), ISGRAPH(3c), ISLOWER(3c), ISPRINT(3c), ISPUNCT(3c), ISSPACE(3c), ISUPPER(3c), and ISXDIGIT(3c); but for a string as well as an array of strings.
o STRING : The string to search in for an unmatched character. o SET : The set of characters that must be matched. o BACK : The direction to look for an unmatched character. The left‐most unmatched character position isreturned unless BACK is present and [char46]false., which causes the position of the right‐most unmatched character to be returned instead of the left‐most unmatched character.
If all characters of STRING are found in SET, the result is zero.If STRING is of zero length a zero (0) is always returned.
Otherwise, if an unmatched character is found The position of the first or last (if BACK is .false.) unmatched character in STRING is returned, starting with position one on the left end of the string.
Sample program I:
program demo_verify ! general examples use M_unicode, only : assignment(=) use M_unicode, only : ut=>unicode_type, ch=>character use M_unicode, only : write(formatted) use M_unicode, only : operator(==) use M_unicode, only : verify, replace use M_unicode, only : operator(//) implicit none ! some useful character sets character,parameter :: & & int*(*) = "1234567890", & & low*(*) = "abcdefghijklmnopqrstuvwxyz", & & upp*(*) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", & & punc*(*) = "!""#$%&()*+,‐./:;<=>?@[\]_‘{|}˜", & & blank*(*) = " ", & & tab = char(11), & & prnt*(*) = int//low//upp//blank//punc ! type(ut) :: stru integer :: i print *, "basics:" print *, VERIFY ("ABBA", "A") ! has the value 2. print *, VERIFY ("ABBA", "A", BACK = .TRUE.) ! has the value 3. print *, VERIFY ("ABBA", "AB") ! has the value 0. ! print *,"find first non‐uppercase letter" ! will produce the location of "d", because there is no match in UPP write(*,*) "something unmatched",verify(ut("ABCdEFG"), upp) ! print *,"if everything is matched return zero" ! will produce 0 as all letters have a match write(*,*) & & "everything matched",verify(ut("ffoorrttrraann"), "nartrof") ! print *,"easily categorize strings as uppercase, lowercase, ..." ! C-like functionality but does entire strings not just characters write(*,*)"isdigit 123?",verify(ut("123"), int) == 0 write(*,*)"islower abc?",verify(ut("abc"), low) == 0 write(*,*)"isalpha aBc?",verify(ut("aBc"), low//upp) == 0 write(*,*)"isblank aBc dEf?",verify(ut("aBc dEf"), blank//tab ) /= 0 ! check if all printable characters stru="aB;cde,fgHI!Jklmno PQRSTU vwxyz" write(*,*)"isprint?",verify(stru,prnt) == 0 ! ! this now has a nonprintable tab character in it stru=replace(stru,10,10,ut(char(11))) write(*,*)"isprint?",verify(stru,prnt) == 0 ! print *,"VERIFY(3) is very powerful using expressions as masks" ! verify(3) is often used in a logical expression stru=" This is NOT all UPPERCASE " write(*,*)"all uppercase/spaces?",verify(stru, blank//upp) == 0 stru=" This IS all uppercase " write(*,*) "stru=["//stru//"]" write(*,*)"all uppercase/spaces?",verify(stru, blank//upp) == 0 ! ! set and show complex stru to be tested stru=" Check this out. Let me know " ! show the stru being examined write(*,*) "stru=["//stru//"]" write(*,*) " "//repeat(int,4) ! number line ! ! function returns a position just not a logical like C print *, "returning a position not just a logical is useful" ! which can be very useful for parsing strings write(*,*)"first non‐blank character",verify(stru, blank) write(*,*)"last non‐blank character",verify(stru, blank,back=.true.) write(*,*)"first non‐letter non‐blank",verify(stru,low//upp//blank) ! !VERIFY(3) is elemental (can check an array of strings in one call) print *, "elemental" ! are strings all letters (or blanks)? write(*,*) "array of strings",verify( & ! strings must all be same length, so force to length 10 & [character(len=10) :: "YES","ok","000","good one","Nope!"], & & low//upp//blank) == 0 ! ! rarer, but the set can be an array, not just the strings to test ! you could do ISPRINT() this (harder) way :> write(*,*)"isprint?", & & .not.all(verify(ut("aBc"), [(char(i),i=32,126)])==1) ! instead of this way write(*,*)"isprint?",verify(ut("aBc"),prnt) == 0 ! end program demo_verifyResults:
> basics: > 2 > 3 > 0 > find first non‐uppercase letter > something unmatched 4 > if everything is matched return zero > everything matched 0 > easily categorize strings as uppercase, lowercase, ... > isdigit 123? T > islower abc? T > isalpha aBc? T > isblank aBc dEf? T > isprint? T > isprint? F > VERIFY(3) is very powerful using expressions as masks > all uppercase/spaces? F > string=[ This IS all uppercase ] > all uppercase/spaces? F > string=[ Check this out. Let me know ] > 1234567890123456789012345678901234567890 > returning a position not just a logical is useful > first non‐blank character 3 > last non‐blank character 29 > first non‐letter non‐blank 17 > elemental > array of strings T T F T F > isprint? T > isprint? TSample program II:
Determine if strings are valid integer representations
program fortran_ints use M_unicode, only : ut=>unicode_type,assignment(=) use M_unicode, only : adjustr, verify, trim, len use M_unicode, only : write(formatted) use M_unicode, only : operator(.cat.) use M_unicode, only : operator(==) implicit none integer :: i character(len=*),parameter :: asciiints(*)=[character(len=10) :: & "+1 ", & "3044848 ", & "30.40 ", & "September ", & "1 2 3", & " -3000 ", & " "] type(ut),allocatable :: ints(:) if(allocated(ints))deallocate(ints) allocate(ints(size(asciiints))) ! gfortran bug ints=asciiints ints=trim(ints) ! show if strings pass or fail the test done by isint(3) write(*,"(is integer?)") do i=1,size(ints) write(*,("|",DT,T14,"|",l1,"|")) ints(i), isint(ints(i)) enddo ! elemental write(*,"(*(g0,1x))") isint(ints)Results:contains
impure elemental function isint(line) result (lout) use M_unicode, only : adjustl, verify, trim ! ! determine if string is a valid integer representation ! ignoring trailing spaces and leading spaces ! character(len=*),parameter :: digits="0123456789" type(ut),intent(in) :: line type(ut) :: name logical :: lout lout=.false. ! make sure at least two characters long to simplify tests name=adjustl(line).cat. ! blank string if( name == )return ! allow one leading sign if( verify(name%sub(1,1),ut(+‐-)) == 0 ) name=name%sub(2,len(name)) ! was just a sign if( name == )return lout=verify(trim(name), digits) == 0 end function isint
end program fortran_ints
> is integer? > |+1 |T| > |3044848 |T| > |30.40 |F| > |September |F| > |1 2 3 |F| > | ‐3000 |T| > | |F| > T T F F F T FSample program III:
Determine if strings represent valid Fortran symbol names
program fortran_symbol_name use M_unicode, only : ut=>unicode_type, trim, verify, len use M_unicode, only : ch=>character use M_unicode, only : write(formatted) implicit none integer :: i type(ut),allocatable :: symbols(:) symbols=[ & ut(A_), ut(10), ut(a10), ut(September), ut(A B), & ut(_A), ut( )]Results:do i=1,size(symbols) write(*,(1x,DT,T11,"|",l2))symbols(i),fortran_name(symbols(i)) enddo
contains
impure elemental function fortran_name(line) result (lout) ! ! determine if a string is a valid Fortran name ! ignoring trailing spaces (but not leading spaces) ! character(len=*),parameter :: int="0123456789" character(len=*),parameter :: lower="abcdefghijklmnopqrstuvwxyz" character(len=*),parameter :: upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" character(len=*),parameter :: allowed=upper//lower//int//"_"
type(ut),intent(in) :: line type(ut) :: name logical :: lout name=trim(line) if(len(name).ne.0)then ! first character is alphameric lout = verify(name%sub(1,1), lower//upper) == 0 & ! other characters are allowed in a symbol name & .and. verify(name,allowed) == 0 & ! allowable length & .and. len(name) <= 63 else lout = .false. endif end function fortran_name
end program fortran_symbol_name
> A_ | T > 10 | F > a10 | T > September| T > A B | F > _A | F > | FSample program IV:
check if string is of form NN‐HHHHH
program form ! ! check if string is of form NN‐HHHHH ! use iso_fortran_env, only : stdout => output_unit use M_unicode, only : verify, unicode_type, assignment(=) use M_unicode, only : ut=>unicode_type implicit none character(len=*),parameter :: g=(*(g0,1x)) ! character(len=*),parameter :: int=1234567890 character(len=*),parameter :: hex=abcdefABCDEF0123456789 logical :: lout type(unicode_type) :: chars type(unicode_type) :: str ! chars=32‐af43d lout=.true. ! ! are the first two characters integer characters? str = chars%character(1,2) lout = (verify( str, ut(int) ) == 0) .and.lout ! ! is the third character a dash? str = chars%character(3,3) lout = (verify( str, ut(‐-) ) == 0) .and.lout ! ! is remaining string a valid representation of a hex value? str = chars%character(4,8) lout = (verify( str, ut(hex) ) == 0) .and.lout ! if(lout)then write(stdout,g)trim(chars%character()), passed else write(stdout,g)trim(chars%character()), failed endif end program formResults:
> 32‐af43d passedSample program V:
exploring uses of elemental functionality and dusty corners
program more_verify use M_unicode, only : ut=>unicode_type, verify use M_unicode, only : assignment(=) use M_unicode, only : ch=>character implicit none character(len=*),parameter :: & & low="abcdefghijklmnopqrstuvwxyz", & & upp="ABCDEFGHIJKLMNOPQRSTUVWXYZ", & & blank=" " ! note character variables in an array have to be of the same length type(ut),allocatable :: strings(:) type(ut),allocatable :: sets(:)Results:strings=[ut("Go"),ut("right"),ut("home!")] sets=[ut("do"),ut("re"),ut("me")]
! elemental ‐‐ you can use arrays for both strings and for sets
! check each string from right to left for non‐letter/non‐blank write(*,*)"last non‐letter",verify(strings,upp//low//blank,back=.true.)
! even BACK can be an array ! find last non‐uppercase character in "Go" ! and first non‐lowercase in "right" write(*,*) verify(strings(1:2),[upp,low],back=[.true.,.false.])
! using a null string for a set is not well defined. Avoid it write(*,*) "null",verify("for tran ", "", .true.) ! 8,length of string? ! probably what you expected write(*,*) "blank",verify("for tran ", " ", .true.) ! 7,found ’n’
! first character in "Go " not in "do", ! and first letter in "right " not in "ri" ! and first letter in "home! " not in "me" write(*,*) verify(strings,sets)
end program more_verify
> last non‐letter 0 0 5 > 2 0 > null 9 > blank 8 > 1 2 1
Functions that perform operations on character strings, return lengths of arguments, and search for certain arguments:
o ELEMENTAL: ADJUSTL(3), ADJUSTR(3), INDEX(3), SCAN(3), o NONELEMENTAL: LEN_TRIM(3), LEN(3), REPEAT(3), TRIM(3)
John S. Urban
