#' Use Friendly Grep/Gsub
#'
#' @param expr expression to be modified.
#' @param value = 1 to print the first matches for each of \code{...}.
#' @param rule replacement rule to be applied in terms of pattern names.
#' @param rep # of times that the pattern and the rule apply.
#' @param ... patterns of the form: name=pattern w/o enclosing parens. \cr
#' No positional arguments are allowed.
#' @param out_pattern = 1 to output pattern and replacement rule
#' to be used in \code{gsub}.
#' @param sep  A character which separates each element of the rule.
#' @param fixed fixed parameter to \code{gsub}.
#' @param debug = 1 to print useful info
#'
#' @details
#'
#'  When \code{value=1} this function interprets \code{...} and
#'  print the first match to each element of \code{...}.
#'
#'  When \code{rule} is given,
#'  this function interprets \code{...} and \code{rule} and generates
#'  the pattern and the replacement for \code{gsub} function.
#'
#'  You can use this function in your program code to perform the replacement,
#'  or, you can use this to generate the pattern and the replacement for
#'  \code{gsub} function to be used later with \code{out_pattern=1} option.
#'
#'  The names in ... can be anything as long as they are valid variable names
#'  except for  \code{rep,value,out_pattern, split, fixed, debug}.
#'  \code{name=".v"} and \code{name=".n"} can be used for a valid variable name
#'  and a number, resp.. \cr
#'  All of the named arguments in ...  will be concatenated in the order
#'  of appearance and will be used as the pattern to match.
#'
#'  \code{rule} can contain any string separated by \code{sep}.
#'  If the string matches one of \code{name} elements, the string
#'  will be replaced by the pattern assocated with that name.#'
#'
#'  In the original \code{gsub} function,
#'  the values in ... will be denoted as 1, 2, ... and
#'  these numbers must be used in the rule parameter as \\\\1, \\\\2, ... .
#'
#'  The following pattern names cannot be used \cr
#'  \code{ expr, rule, out_patten, sep, debug}
#'
#' @return
#'  The result of \code{gsub}, or when out_pattern=1, the pattern and the rule
#'  to be used in \code{gsub} in a character vector of length 2.
#'
#' @examples
#' # The third example below generates the following grep/gsub patterns:
#' # gsub(
#' # "(^|[-+\\*`~])([[:alpha:].][[:alnum:]_.]*)(\\*)([0-9]*\\.{0,1}[0-9]*)
#' # ($|([-+*/`~].+))",   "\\1\\4\\3\\2\\5",   "a123+a*17.01-b*34+9" )
#' #
#'
#' # varname*num -> num*varname
#' top <- "^|[-+\\*`~]"; varname <- "[[:alpha:].][[:alnum:]_.]*"; times <- "\\*"
#' num <- "[0-9]*\\.{0,1}[0-9]*"; tail <- "$|([-+*/`~].+)"
#' expr <- "a123+a*17.01-b*34+9"
#'
#' Grep( expr, value=1
#'           , top=top, varname=varname, times=times, number=num, tail=tail )
#' Grep( expr, value=1
#'           , top=top, varname=".v", times=times, number=".n", tail=tail )
#' ( temp <- Grep( expr, rule="top?num?times?varname?tail", out_pattern=1
#'           , top=top, varname=".v", times=times, num=".n", tail=tail ) )
#' Grep( temp, rule="top?num?times?varname?tail"
#'           , top=top, varname=".v", times=times, num=".n", tail=tail )
#' Grep( expr, rule="top?(?num?)?times?varname?tail", rep=2
#'           , top=top, varname==".v", times=times, num=".n", tail=tail )
#'
#' # transposition and trace of a scalar
#' expr <- "+t(09)-tr(123)"
#' Grep( expr, rule="top?sign?digits?tail", debug=1
#'               , top="^|[-+*`~]"
#'               , tparen="t\\(|tr\\("
#'               , sign="[-+]*"
#'               , digits="[0-9]+"
#'               , paren="\\)"
#'               , tail="$|[-+*/`~]", rep=2 )
#'
#'
#' # Cancel x/x etc with back reference
#' top <- "^|[-/+*=`~]"; varnam <- "[[:alpha:].]+[[:alnum:]_]*|[1-9]+[0-9]*"
#' div <- "/\\2"; tail <- "($|[-/+*=`~])"
#' Grep( "17*x12e/x12e*100+a/a+2/2", rule="top?1?tail"
#'     , top=top, varnam=varnam, div=div, tail=tail )
#' Grep( "17*x12e/x12e*100+a/a+2/2", rule="top?1?tail"
#'     , top=top, varnam=varnam, div=div, tail=tail, rep=2 )
#'
#' @export
#'

Grep <- function( expr, rule=NULL, ..., rep=1, value=0, out_pattern=0
                  , split="?", fixed=0, debug=0 ){
 # modify expr by gsub function
 # Shin-ichi Mayekawa
 # 20200529
 # rule by patter name: 20200602,03
 # rep: 20230505cot
 # roxygen2 examples: 20230505cot
 # matched pattern: 20230505cot,0506
 # value: 20230506
 # gsub -> sub in Code: 20230508
 # Gsub in lazy.symboloc\Gsub5.R renamed as Grep: 20230508
 # . added to varname: 20230509dnc
 # Exists abandoned: 20230510
 # varname and number: 20230510
 # lv() removed from examples for version 4.2: 20230625
 #

 # preset values (Not Used)
 varname="[[:alpha:].][[:alnum:]_.]*"
 number="[0-9]*\\.{0,1}[0-9]*"


 # analyze ...
 res=analyze_three_dots( ..., print_the_result=0 )
 pat=unlist(res$val)
 name=res$name
 npat=length(pat)

 # replace .n and .v
 loc=which(pat == ".v")
 pat[loc]=varname
 loc=which(pat == ".n")
 pat[loc]=number

 # enclose each pattern by parens
 pat=unlist( lapply( pat,function(x) paste("(",x,")",sep="") ) )

 # combine all the patterns
 pattern=paste(pat,collapse="")


 if( value == 1 ){

   # matched pattern
   values=numeric(npat)
   for( i in 1:npat ){
     Code=paste("values[",i
                  ,"]=sub(pattern,';\\\\",i,";',expr,fixed=fixed)", sep="")
     eval(parse(text=Code))
   }

   # leftovers before and after pattern
   LocLOL=regexpr(";", values[1])
   LeftOverL=substr(values[1],1,LocLOL-1)
   LocLOR=nchar(values[1])-regexpr(";", revchar(values[1]))+1
   LeftOverR=substring(values[1],LocLOR+1)
   for( i in 1:npat ){
    LocLOL=regexpr(";", values[i])
    LocLOR=nchar(values[i])-regexpr(";", revchar(values[i]))+1
    values[i]=substr(values[i],LocLOL+1,LocLOR-1)
   }

   # append LocLOL and LocLOR
   .name=c("PRE",name,"POST")
   .pat=c("NA",pat,"NA")
   .values=c(LeftOverL,values,LeftOverR)
   Print(npat)
   Print(pattern)
   Print(.name,.pat,.values)

 } # end of value


 if( !is.null(rule) ){

   # split rule by split char
   rule1=unlist(strsplit(rule,split, fixed=1))


   # replace the names in the rule by their values
   df1=data.frame( id1=1:length(name), name, stringsAsFactors=0 )
   df2=data.frame( id2=1:length(rule1), rule1, stringsAsFactors=0 )
   temp=merge( df1, df2, by.x="name", by.y="rule1", all=1 )
   temp1=temp[order(temp$id2),]

   # printm(which(name%in%rule1), which(rule1%in%name))
   # printm(loceq(name,rule1), loceq(rule1,name))
   # printm(df1,df2)
   # printm(temp,temp1)

   locobs=which( !is.na(temp1$id1)[1:length(rule1)] )

   rule2=rule1
   rule2[locobs]=paste("\\",temp1$id1[locobs],sep="")
   rule2[-locobs]=temp1$name[1:length(rule1)][-locobs]

   rule2=paste(rule2,collapse="")

   if( debug >= 2 ){
     Print(name, pat, rule1)
     Print(rule2)
   }

   if( debug ){
     cat("\nbefore=",expr,"\n")
   }


   # replace
   code="expr=gsub(pattern, rule2,  expr, fixed=fixed)"
   for( i in 1:rep ){
     eval(parse(text=code))
     if( debug ){
       cat(" after=",expr,"\n")
     }
   }

   if( out_pattern == 1 ){
     res=c(pattern,rule2)
     names(res)=c("pattern","rule")
     return( res )
   }
   else{
     return( expr )
   }

 } # end of rule


} # end of Grep


