regsub(3f) - [M_regex] perform regex substitutions
subroutine regsub(matchline, matches, source, dest)
character(len=*),intent(in) :: matchline
integer,intent(in) :: matches(:,:)
character(len=*),intent(in) :: source
character(len=:),allocatable,intent(out) :: dest
The regsub() function copies source to dest, making substitutions according to the most recent regexec() performed using MATCHES(:,:).
Each instance of “&” in source is replaced by the substring indicated by the start and end array MATCHES(:,:).
Each instance of “\n”, where n is a digit, is replaced by the substring indicated by MATCHES(1,n) and MATCHES(2,n).
To get a literal “&” or “\n” into dest, prefix it with “"; to get a literal “" preceding “&” or “\n”, prefix it with another “".
MATCHLINE line REGEXEC(3f) was run against
MATCHES output array from REGEXEC(3f) call
SOURCE output template string containing "&" and/or "\n" indicating where to
make substitutions
DEST output string
Sample program that reads an array of lines representing a Unix /etc/passwd file and uses an RE (Regular Expression) to read fields from the line and then uses REGSUB(3f) to print strings using the matched strings
program demo_regsub
use M_regex, only: regex_type, regcomp, regexec, regerror, regmatch, regfree, regsub
implicit none
type(regex_type) :: regex
integer,parameter :: maxmatch=10
integer :: matches(2,maxmatch)
character(len=:),allocatable :: input_line(:)
character(len=:),allocatable :: output_line
character(len=:),allocatable :: expression
logical :: match
integer :: stat
integer :: i
logical :: BRE
! The /etc/passwd file is a colon-separated file that contains the following information:
!
! User name.
! Encrypted password.
! User ID number (UID)
! User's group ID number (GID)
! Full name of the user (GECOS)
! User home directory.
! Login shell.
!
BRE=.true.
if(BRE)then ! BRE (Basic Regular Expression)
expression= '\([^:]*\):*\([^:]*\):*\([^:]*\):*\([^:]*\):*\([^:]*\):*\([^:]*\):*\([^:]*\):*.*'
call regcomp(regex,expression,status=stat)
else ! ERE (Extended Regular Expression)
expression= '([^:]*):*([^:]*):*([^:]*):*([^:]*):*([^:]*):*([^:]*):*([^:]*):*.*'
call regcomp(regex,expression,'x',status=stat)
endif
if(stat.ne.0)then ! if RE did not compile report error
write(*,*)'*regcomp* ERROR:',regerror(regex,stat)
stop 1
endif
! simulate /etc/password file in array, with common aberrant input lines included
input_line= [character(len=128) :: &
"doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh: and more", &
"doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh: and more:", &
"doeqj: :1001: :John Q. Doe:/home/doeqj:/bin/tcsh:", &
"doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh:", &
"doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh", &
"doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj", &
"doeqj:xxxxx:", &
"doeqj:xxxxx", &
"doeqj:", &
"doeqj", &
! the RE shown needs the field to have at least one character
! which should be replaced first, but not shown in this example
": : : : : : : : : : : : : : :", &
": ::", &
"" ]
do i=1,size(input_line)
match=regexec(regex,input_line(i),matches) ! generate the matches array using the compiled RE
write(*,'(a)')repeat('-',80) ! put out a number line
write(*,'(a)') input_line(i)
! replace \n lines
call regsub(input_line(i),matches,'username="\1" &
&password="\2" UID="\3" GID="\4" name="\5" &
&home="\6" shell="\7" ',output_line)
write(*,'(a)') output_line
if(i.eq.1)then ! show other examples of formatting for first entry
call regsub(input_line(i),matches,&
& 'The username for \5 is "\1"',output_line)
write(*,'(a)') output_line
call regsub(input_line(i),matches,&
& 'username "\1" has UID=\3, GID=\4 &
& and default shell "\7"',output_line)
write(*,'(a)') output_line
endif
enddo
call regfree(regex)
end program demo_regsub
--------------------------------------------------------------------------------
doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh: and more
username="doeqj" password="xxxxx" UID="1001" GID="200" name="John Q. Doe" home="/home/doeqj" shell="/bin/tcsh"
The username for John Q. Doe is "doeqj"
username "doeqj" has UID=1001, GID=200 and default shell "/bin/tcsh"
--------------------------------------------------------------------------------
doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh: and more:
username="doeqj" password="xxxxx" UID="1001" GID="200" name="John Q. Doe" home="/home/doeqj" shell="/bin/tcsh"
--------------------------------------------------------------------------------
doeqj: :1001: :John Q. Doe:/home/doeqj:/bin/tcsh:
username="doeqj" password=" " UID="1001" GID=" " name="John Q. Doe" home="/home/doeqj" shell="/bin/tcsh"
--------------------------------------------------------------------------------
doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh:
username="doeqj" password="xxxxx" UID="1001" GID="200" name="John Q. Doe" home="/home/doeqj" shell="/bin/tcsh"
--------------------------------------------------------------------------------
doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj:/bin/tcsh
username="doeqj" password="xxxxx" UID="1001" GID="200" name="John Q. Doe" home="/home/doeqj" shell="/bin/tcsh"
--------------------------------------------------------------------------------
doeqj:xxxxx:1001:200:John Q. Doe:/home/doeqj
username="doeqj" password="xxxxx" UID="1001" GID="200" name="John Q. Doe" home="/home/doeqj" shell=""
--------------------------------------------------------------------------------
doeqj:xxxxx:
username="doeqj" password="xxxxx" UID="" GID="" name="" home="" shell=""
--------------------------------------------------------------------------------
doeqj:xxxxx
username="doeqj" password="xxxxx" UID="" GID="" name="" home="" shell=""
--------------------------------------------------------------------------------
doeqj:
username="doeqj" password="" UID="" GID="" name="" home="" shell=""
--------------------------------------------------------------------------------
doeqj
username="doeqj" password="" UID="" GID="" name="" home="" shell=""
--------------------------------------------------------------------------------
: :: :: :: :: :: :: ::
username="" password=" " UID=" " GID=" " name=" " home=" " shell=" "
--------------------------------------------------------------------------------
: ::
username="" password=" " UID="" GID="" name="" home="" shell=""
--------------------------------------------------------------------------------
username="" password="" UID="" GID="" name="" home="" shell=""
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
character(len=*), | intent(in) | :: | matchline | |||
integer, | intent(in) | :: | matches(:,:) | |||
character(len=*), | intent(in) | :: | source | |||
character(len=:), | intent(out), | allocatable | :: | dest |
subroutine regsub(matchline,matches, source, dest) ! ident_6="@(#) M_regex regsub(3f) perform regex substitutions" character(len=*),intent(in) :: matchline integer,intent(in) :: matches(:,:) character(len=*),intent(in) :: source character(len=:),allocatable,intent(out) :: dest character(len=:),allocatable :: src character(len=1) :: c character(len=1) :: cc integer :: no integer :: len integer :: i logical :: skip integer,parameter :: inine=ichar('9'), izero=ichar('0') !!if(debug)then !! write(*,'(a,*(i0.3:,","))')'MATCHES(1,:)=',matches(1,:) !! write(*,'(a,*(i0.3:,","))')'MATCHES(2,:)=',matches(2,:) !! write(*,*)'SOURCE=['//SOURCE//'] LEN=',len(SOURCE) !!endif if(source.eq.'')then dest='' write(ERROR_UNIT,*)"*regsub* NULL parameter to regsub" return endif src = source//' ' dest = '' skip=.false. do i=1,len(source) if(skip)then skip=.false. cycle endif c=src(i:i) cc=src(i+1:i+1) if (c == '&')then ! & is replaced by match 1 if(any(matches(:,1).le.0))cycle dest=dest//matchline( matches(1,1):matches(2,1) ) cycle elseif (c == '\' .and. (ichar(cc) >= izero .and. ichar(cc) <= inine) )then ! \[0-9] is replaced by match 1 to 10 no = ichar(cc) - ichar('0') if(.not.any(matches(:,no+1).le.0))then dest=dest//matchline( matches(1,no+1):matches(2,no+1) ) endif skip=.true. cycle elseif (c == '\' .and. (cc == '\' .or. cc == '&'))then ! escaping literal ("\\" or "\&") skip=.true. cycle else dest=dest//c ! non-escaped ordinary character endif enddo end subroutine regsub