In its simplest form PInStr is nearly identical to instr, with the exception that the default search with PInStr is case-insensitive whereas InStr is always case-sensitive. This PInStr default can be reverted, see "flags" above.PInStr usage: wrote: first = PInStr( [ start, ] str, pattern [ ,flags ] )
Parameters:
str
..The string to be searched.
pattern
..The pattern to find. Use extended regular expressions.
start
..The position in str at which the search will begin. Optional.
flags
..Only one currently, integer, optional:
....1. 128 = turn on case-sensitivity
Return Values:
first
..The integer return value from PInStr, where:
....<0 = an error occurred
......if = -4 then the regexp compilation failed (your regexp is bad) and
........the error/reason string will be in PInStrData.errStr
....0 = match not found
....>0 = the position of the matched pattern and
......the matched substring will be in PInStrData.match
..Aso returns a UDT which is populated in the global namespace. See pinstr.bi, "tagPInStrData"
Simple:
Code: Select all
#include once "pinstr.bi"
print PInStr("John Doe","doe")
Code: Select all
#include once "pinstr.bi"
print PInStr("John Doe","Doe",128) '128 is defined as PInStrCaseSenSe
Moving beyond simple, PInStr can utilize the power of regular expressions. It's beyond the current scope and my patience to try to explain regular expressions - you can start your education if needed with wikipedia:
http://en.wikipedia.org/wiki/Regular_expression
There are regexp examples on wiki, also, but they are perl-oriented. PInStr uses regexec() which is (theoretically) POSIX 2 compliant ==> perl, python, and other langs expand POSIX 2 regexps in unconforming ways.
I'll try to offer better details of how to use grouping, (), later, as PInStr can use grouping and the usage is not obvious. Hopefully the example progs below will provide enough clues to get someone started who is familiar with regexps.
Need pinstr.bi:
Code: Select all
'pinstr.bi
'CaSe-InSensitive InStr using extended regexp
'PInStr, "Patterned" case-insensitive InStr using extended regular expressions
'UpDate:
' 2009-04-24 Added PInput,PSplit_csv,PSearchReplace
'
'lib:
#include once "regex.bi"
'flags:
#define PInStrCaseSenSe 128 'override using default case-insensitivity
'
'====================================== pinput()
type tagPInStrData
match as string 'the portion of the target string that matched
groups as integer 'the number of groups, (), in your regexp
group(1 to 12) as string 'the matched groups/substrings
position as integer 'the position of the first match in target,
' or errorcode
errCode as integer 'same as .position but errorcode only
errStr as string*64 'if .errCode = -4 then then your regexp is flawed,
' it wouldn't compile, this is an English
' explanation of the error
end type
dim shared PInStrData as tagPInStrData
'
declare function PInStr overload (_
ByRef targStr as string,_
ByRef pattern as string,_
ByVal flags as integer=0) as integer
'
declare function PInStr (_
ByVal start as integer,_ 'same as instr(start,
ByRef targStr as string,_ 'same as instr(,str,
ByRef pattern as string,_ 'same as instr(,,substring
ByVal flags as integer=0) as integer '128 = CaSe-Sensitive search
'
function PInStr overload (_
ByRef targStr as string,_
ByRef pattern as string,_
ByVal flags as integer=0) as integer
'
return PInStr(1,targStr,pattern,flags)
'
end function
'
function PInStr (_
ByVal start as integer,_
ByRef targStr as string,_
ByRef pattern as string,_
ByVal flags as integer=0) as integer
'
With PInStrData
'
if targStr="" then
.errStr="Target string is BLANK"
.errCode= -1
return -1
end if
'
if pattern="" then
.errStr="Pattern string is BLANK"
.errCode= -2
return -2
end if
'
.match=""
'.group(1 to remax)
.position=0
.errCode=0
.errStr=space(128)
'
dim as integer c,l,remax=12,res,rflag,tn,tp,tres
dim as string zs
static as string lastpattern
dim as zstring ptr pbuff
static as regex_t re
dim pm(0 to remax) as regmatch_t
'
if start<1 then start=1
l=*(cptr(integer ptr,@targStr)+1)
if start>l then
.errStr="START must be <= len(Target)"
.errCode= -3
return -3
end if
'
if not flags and 128 then rflag or=REG_ICASE
rflag or= 1
'
if lastpattern<>pattern then
regfree(@re)
lastpattern=pattern
res=regcomp(@re,pattern,rflag)
if res<>0 then
'print res;" ==> regcomp failure: ";pattern
.errCode=res
tres=regerror(res,@re,strptr(.errStr),64)
return -4
end if
end if
'
pbuff=strptr(targStr)
if start>1 then pbuff+=start
'
tn=re.re_nsub
if tn>remax then tn=remax
remax=tn
.groups=tn
if tn=0 then tn=1 else tn+=1
'
res=regexec(@re,pbuff,tn,@pm(0),0)
'
if res<>0 then return 0 'aw, not found..
'
zs=mid(*pbuff,1+pm(0).rm_so,pm(0).rm_eo-pm(0).rm_so)
tp=pm(0).rm_so
if start>1 then tp+=start
'
for c=0 to remax
.group(c+1)=mid(*pbuff,1+pm(c+1).rm_so,pm(c+1).rm_eo-pm(c+1).rm_so)
next
'
tp+=1
.match=zs
.position=tp
'
return tp
'
end With
'
end function
'
'====================================== PInput()
declare function _
PInput(_
pt as string,_ 'pattern for entry
r as integer,_ 'row for entry
c as integer,_ 'column for entry
imax as integer,_ 'max len of entry not including prompt
iprompt as string,_ 'prompt for entry
caseS as integer=0_ 'if 128 then match is Case-SenSitive
) as string
'
function _
PInput(_
pt as string,_
r as integer,_
c as integer,_
imax as integer,_
iprompt as string,_
caseS as integer=0_
) as string
'
dim as integer f,k,lm,res,t
dim as string ks,ts
'
if caseS>0 then caseS=128
'
locate r,c
print iprompt;
locate r,c+len(iprompt)
print string(imax,"_");
locate r,c
print"Phone: ";
lm=pos
while (1)
k=getkey
select case k
case 8
if pos>k then
locate r,pos-1
print " ";
locate r,pos-1
ts=left(ts,len(ts)-1)
end if
case 32 to 122
if pos<=imax+lm then
print chr(k);
ts+=chr(k)
else
beep
end if
case 13
ts=trim(ts)
if ts>"" then
res=pinstr(ts,pt,caseS)
if res then
exit while
else
beep
end if
else
beep
end if
case 27
f=1
exit while
case else
beep
end select
wend
'
if f=1 then
return "*Entry Canceled*"
else
return ts
end if
'
end function
'
'====================================== psplit_csv()
declare function _
PSplit_csv(_
targStr as string,_ 'string to parse/delmit
targArray() as string,_ 'array to parse targStr TO
delimiter as string=","_'delimiter used as.. delimiter
) as integer 'returns number of array els used, ONE-based
'
function _
PSplit_csv(_
targStr as string,_
targArray() as string,_
delimiter as string=","_
) as integer
'
if TargStr="" then return -1
if delimiter="" or len(delimiter)>1 then return -2
if delimiter=!"""or delimiter="" then return -3
'
dim as integer c,p,maxarray,res
dim as string pt,ts
'
maxarray=ubound(targArray)
'
pt= !"(^|" _
& "" & delimiter & _
!")("([^"]+|"")*"|[^" _
& "" & delimiter & _
"]*)"
'
with PInStrData
'
c=1
p=pinstr(targStr,pt)
while p>0
if left(.match,1)=delimiter and len(.match)>1 then
targArray(c)=""
c+=1
targArray(c)=trim(.match,ANY delimiter & " ")
else
targArray(c)=.match
end if
if .match=delimiter then
targArray(c)=""
c+=1
targArray(c)=""
end if
c+=1:if c>=maxarray then exit while
p+=len(.match)
p=pinstr(p,targStr,pt)
wend
'
end with
'
return iif(c>1,c-1,0)
'
end function
'
'====================================== PSearchReplace()
declare function _
PSearchReplace(_
targStr as string,_ 'string to parse
params as string,_ 'parameter string, replacements
paramdelimiter as string="=",_ 'char used to delimit param string
caseS as integer=0_ 'if 128 then is Case-SenSitive search/replace
) as string
'
function _
PSearchReplace(_
targStr as string,_
params as string,_
paramdelimiter as string="=",_
caseS as integer=0_
) as string
'
dim as integer c,cta,lp,op,p,res,tres
dim as string ns,pt,ts
dim as string ma(1 to 2,256),pa(24),ta(256)
'
if paramdelimiter="" then paramdelimiter="="
'
res=PSplit_csv(params,pa())
if res=0 then return targStr
for c=1 to res
tres=PSplit_csv(trim(pa(c),chr(34)),ta(),paramdelimiter)
ma(1,c)=ta(1)':print ta(1)
ma(2,c)=ta(2)':print ta(2)
next
'
ns=targStr
'
with PInStrData
'
for cta=1 to res
pt=ma(1,cta)
ts=""
lp=1
op=0
p=pinstr(ns,pt,caseS)':print p
if p=0 then continue for
while p>0
if p then
ts+=mid(ns,lp,p-lp)
if len(ma(2,cta))>0 then
ts+=ma(2,cta)
end if
lp=p+len(.match)
end if
p+=len(.match)
op=p
p=pinstr(p,ns,pt,caseS)
wend
'
if len(ts)<op then
ts+=mid(ns,op,255)
end if
'
ns=ts
next cta
'
return ns
'
end with
'
end function
Examples:
Code: Select all
'pinstr.bas Example
'CaSe-InSensitive InStr using extended regexp
'PInStr, "Patterned" case-insensitive InStr using extended regular expressions
'
#include once "pinstr.bi"
'
dim as integer p,res
dim as string targStr,pattern,uf
'
'return all matches
targStr="Now is the time for all good men to come to the aid of the party"
print targStr
pattern="no|go|to|party"
'
res=99:p=1
uf="At: ### found: \ \ using: &"
while res>0
'search from position p, no grouping, default case insensitive
res=PInstr(p,targStr,pattern)
if res>0 then
print using uf;res,PInStrData.match,pattern
p=res+1
end if
wend
'
'
print
print "==========================================="
targStr="Brown, Robert Z. 808-555-1212 123 Easy Street Lahaina, HI 96761"
print targStr
'
'get last name, first &
pattern="^([^0-9]*) "
' search from default start position 1, return 1st matching group
res=PInStr(targStr,pattern)
print PInStrData.group(1)
'
'get last name
pattern="^[^0-9,]*"
' search using defaults, start position 1 no grouping
res=PInStr(targStr,pattern)
print PInStrData.match
'
'get first name
pattern="(, )(\D*)"
' search from default start position 1, return 2nd matching group
res=PInStr(targStr,pattern)
print PInStrData.group(2)
'
'get phone number US format no country code
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
res=PInStr(targStr,pattern)
print PInStrData.match
'
'get state code/abbreviation, trims leading space
pattern=" ([A-Z]{2} .*)$"
' default start position 1, return 1st matching group, CASE SENSITIVE search
res=PInStr(targStr,pattern,128)
print PInStrData.group(1)
'
'get zip code
pattern="[-0-9]{5,9}$"
res=PInStr(targStr,pattern)
print PInStrData.match
'
'using one regexp
dim z as tagPInStrData ptr=@PInStrData 'shorten calls..
print
pattern="^([^0-9,]*), ([^0-9,]*) +([0-9]{3}-[0-9]{3}-[0-9]{4}) +" & _
"(.*) (.*)$"
'
res=PInStr(targStr,pattern)
if res then
print z->groups;" Groupings found in string/pattern:"
print
for c as integer=1 to z->groups
print c,z->group(c)
next
print
print "2+1 ";z->group(2);" ";z->group(1)
print " 4 ";z->group(4)
print " 5 ";z->group(5)
print
print " 3 ";z->group(3)
else
print "Match not found"
end if
sleep
end
ETA: New version 2009-04-21
ETA: New Version 2009-04-24 PInstr(),PInput(),PSplit_csv() and PSearchReplace() all moved
.. into pinstr.bi, examples modified accordingly