#' Read Lines or Wite Lines with or without Encoding Option
#'
#' @param filename an input text file name
#' @param encoding = "Shift-JIS" | "UTF-8" | NULL
#' where NULL is for system default and should be equal to "native.enc".
#' @param text a text vector to be written
#' @param asDBCS = 1 to create double byte characters when
#'  encoding="Shift-JIS" is specified.
#' @param ... aditional parameters to readLines and writeLines
#'
#' @details
#' Note that, as described in the Arguments section of native readLines,
#' specifying encoding option when calling readLines cannot read lines
#' from a file using the specified encoding. \cr
#' This function specifies encoding when defining the connection
#' and closes it upon return.
#'
#' The following code
#' \preformatted{
#'  con <- file( filename, encoding="Shift-JIS" )
#'  return( readLines( con, ... )  )
#' }
#' makes the Zenkaku characters 3 byte chracters.
#' Therefore, when asDBCS=1, native \code{readLines} will be used.
#'
#' When writing UTF-8 characters which are not included in native encoding,
#' specify \code{useBytes=TRUE} option.\cr
#' Check to see that \code{Encoding(text)} returns "UTF-8", not "unknown".
#'
#' Above can avoid the following default action of \code{writeLines}:
#' \preformatted{
#'  useBytes is for expert use. Normally (when false) character strings with
#'  marked encodings are converted to the current encoding before being passed
#'  to the connection (which might do further re-encoding).
#'  useBytes = TRUE suppresses the re-encoding of marked strings so they are
#'  passed byte-by-byte to the connection: this can be useful when strings
#'  have already been re-encoded by e.g. iconv.
#'  (It is invoked automatically for strings with marked encoding "bytes".)
#'  }
#'
#' @examples
#' # In the examples below, TestData1.txt is encoded in Shift-JIS
#' # and  TestData2.txt, in UTF-8. The last line of TestData2.txt contains
#' # non Shif-JIS characters.
#' #
#' # These files are stored in the folder where lazy.tools package is stored.
#'
#' # reading Shift-JIS files on from R.4.1.3
#' nobs <- 10
#' infile1 <- system.file("TestData1.txt",package="lazy.tools")
#' if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 ){
#'  temp1 <- ReadLines(infile1, n=nobs+2)[-(1:2)]
#' } else{
#'  # The result will be Double Byte.
#'  temp1 <- ReadLines(infile1, n=nobs+2, asDB=1)[-(1:2)]
#'  # The result will be Triple Byte.
#'  temp11 <- ReadLines(infile1, n=nobs+2)[-(1:2)]
#'
#'  nbyte(temp1)
#'  nbyte(temp11)
#'  identical(temp1[-nobs],temp11[-nobs])  # true
#'  identical(nbyte(temp1[-nobs]),nbyte(temp11[-nobs])) # false
#' }
#'
#'
#'
#' # reading UTF-8
#' nobs <- 10
#' infile2 <- system.file("TestData2.txt",package="lazy.tools")
#' temp2 <- ReadLines(infile2, n=nobs+2, encoding="UTF-8")[-(1:2)]
#' nbyte(temp2)
#'
#' identical(temp1[-nobs],temp2[-nobs])  # true
#' if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) <= 0 ){
#'  identical(temp11[-nobs],temp2[-nobs])  # true
#'  identical(nbyte(temp11[-nobs]),nbyte(temp2[-nobs]))  # false
#' }
#'
#'
#'
#' # reading UTF-8 with BOM
#' nobs <- 10
#' infile3 <- system.file("TestData3.txt",package="lazy.utf8")
#' temp3 <- ReadLines(infile3, n=nobs+2, encoding="UTF-8")[-(1:2)]
#' nbyte(temp3)
#' identical(temp2[-nobs],temp3[-nobs])  # true
#'
#'
#'
#' \dontrun{
#' # These two work
#' WriteLines( temp1, "temp11.txt" )
#' WriteLines( temp1, "temp12.txt", encoding="UTF-8" )
#'
#' # These two work exept for the last obs which has non Shift-JIS characters.
#' WriteLines( temp2, "temp21.txt" )
#' WriteLines( temp2, "temp22.txt", encoding="UTF-8"  )
#'
#' # This works.
#' con <- file( "temp222.txt", encoding="native.enc" )
#' writeLines( temp2, con , useBytes=TRUE )
#' close(con)
#' }
#'
#'
#' # creating data frame using column specifications
#' # column spec
#' from <- c(1, 7,25,26,27,28,29,30,31,32,34)
#' to <-   c(5,23,25,26,27,28,29,30,31,32,39)
#' name <- c("id", "name",paste("Q",1:8,sep=""),"comment")
#'
#' # convert to a character matrix by stacking each row (record, observation)
#' datamat2 <- Reduce( rbind, substr2(temp2, from,to), init=NULL )
#' colnames(datamat2) <- name
#' # matrix to data frame
#' df2 <- as.data.frame(datamat2)
#'
#' # Alternative way by stacking each column (variable)
#' datamat22 <- Reduce( cbind, mapply( function(x,y) substr2(temp2,x,y)
#'                    , from, to, SIMPLIFY=FALSE ), init=NULL )
#' colnames(datamat22)=name
#' # matrix to data frame
#' df22 <- as.data.frame(datamat22)
#'
#' identical(datamat2,datamat22)  # true
#' identical(df2,df22)  # true
#'
#' print(datamat2)
#'
#' # character to numeric conversion
#' df2[,paste("Q",1:8,sep="")] <- apply(df2[,paste("Q",1:8,sep="")],2
#'                                     ,as.numeric)
#' str(df2)
#'
#' # cannto print UTF-8 data frame nicely by native print.data.frame.
#' print(df2)
#' print.listof(df2)
#'
#'
#' @return ReadLines returns a vector of strings.
#'
#' @export
#'

ReadLines <- function( filename, encoding="Shift-JIS", asDBCS=0, ... ){
 # Read Lines with encoding
 # Shin-ichi Mayekawa
 # 20220811cot,12cot
 # asDBCS: 20220818
 # rozygen2 example: 20220823
 #

 # This enables the use of DBCS.
 if( encoding == "Shift-JIS"  &&  asDBCS == 1 ){
   return( readLines( filename, ... ) )
 }

 # in order to close the connection, it seems necessary to define an object
 if( !is.null(encoding) ){
  con=file( filename, encoding=encoding )
 }
 else{
  con=file( filename )
 }

 # close connection upon return
 on.exit(close(con))

 return( readLines( con, ... )  )

} # end of ReadLines



#' @rdname ReadLines
#' @export
#'

WriteLines <- function( text, filename, encoding="Shift-JIS", ... ){
 # Wite Lines with encoding
 # Shin-ichi Mayekawa
 # 20220811cot,12cot
 #

 # in order to close the connection, it seems necessary to define an object
 if( !is.null(encoding) ){
  con=file( filename, encoding=encoding )
 }
 else{
  con=file( filename )
 }

 # close connection upon return
 on.exit(close(con))

 writeLines( text, con, ... )

 invisible( NULL )

} # end of WriteLines





#' Returns the number of bytes used to represent each character
#' in each of the string.
#'
#' @param x String vector
#'
#' @return a list consisting of the number of bytes per character
#'
#' @details
#' Let x = "abc". The core of this function is \cr
#' \code{lapply(
#'   strsplit(x,""), function(y) unlist(lapply(lapply(y,charToRaw),length))
#'   ) } \cr
#' It counts the length of the Raw Expression of each character.
#'
#' About rawToChar and charToRaw functions: \cr
#' To get the raw expression of character, use\cr
#' \code{ raw <- charToRaw(paste(c(0:9," ",letters,LETTERS),collapse="")) }\cr
#' To get the numeric equivalent of raw, use\cr
#' \code{ num <- as.numeric(raw) }.\cr
#' To recover the original characters, use\cr
#' \code{ char <- rawToChar( as.raw(num) ) }.\cr
#'
#' @examples
#' # Example of one, two, three amd four byte characters on UTF-8 machines
#' if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 ){
#'  num=c(97, 206, 177, 227, 129, 130, 240, 160, 174, 183)
#'  char=num2char(num)
#'  nbyte(char)
#' }
#'
#' # A string consisting of single and multi byte characters
#' # The 3rd, 6th and 7th characters are uppercase Zenkaku Romans.
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nza <- c(97, 98, 239, 188, 163, 100, 101, 239, 188, 166, 239, 188, 167, 104)
#' else
#'  nza <- c(97,98,130,98,100,101,130,101,130,102,104)}
#' za <- rawToChar(as.raw(nza))
#'
#' # location of the multi byte characters
#' nchar(za)
#' is.DBCS(za)
#' printm( nchar(za), length(charToRaw(za)), nchar2(za) )
#' sza=unlist(strsplit(za,""))
#' printm(sza,nbyte(za),is.DBCS(za))
#'
#' cat("When using Shif-JIS encoding, ",
#'     "it seems that 'strsplit' makes the result 3 byte characters.\n")
#' printm(sza,unlist(nbyte(sza)),unlist(is.DBCS(sza)))
#' psza <- paste(sza,collapse="")
#' printm(sza,nbyte(psza),is.DBCS(za))
#'
#' identical(za,psza)
#' identical(nbyte(za),nbyte(psza))
#'
#' # Instead of strsplit, use below
#' sza2 <- substring(za,1:nchar(za),1:nchar(za))
#' printm( sza, unlist( nbyte( sza2 ) ) )
#' psza2 <- paste(sza2,collapse="")
#' nbyte(psza2)
#'
#' identical(za,psza2)
#' identical(nbyte(za),nbyte(psza2))
#'
#'
#' @export
#'

nbyte <- function( x ){
 # returns a list of the # of bytes in a string vector
 # Shin-ichi Mayekawa
 # 20170703
 # nbyte: 20220811cot
 # avoid strsplit: 20220818
 # use nchar with width=: 20220819
 # rozygen2 example: 20220823
 # new method: 20220826
 #

 #
 # old version: strsplit makes the result 3 byte characters!!!
 # nbyte=lapply( strsplit(x,"")
 #             , function(y) unlist(lapply(lapply(y,charToRaw),length)) )
 #
 # old version: better use nchar with byte option
 # nbyte=lapply( x, function(y){
 #  res=numeric(nchar(y))
 #  for( i in 1:nchar(y) ){
 #   res[i]=length(charToRaw(substr(y,i,i)))
 #  }
 #  return( res )
 #  }
 # )

  nbyte=lapply( x, function(y){
    unlist(lapply(1:nchar(y), function(i){nchar(substr(y,i,i), type="byte")} ))
  } )

 if( length(nbyte) == 1 ) nbyte=unlist(nbyte)
 return( nbyte  )

} # end of nbyte




#' Count the number of characters using bytes, not characters, as the unit.
#'
#' @param x A string
#'
#'
#' @details
#'
#' This function is equivalent to native nchar function with type="byte"
#' option.
#'
#'
#' About rawToChar and charToRaw functions: \cr
#' To get the raw expression of character, use\cr
#' \code{ raw <- charToRaw(paste(c(0:9," ",letters,LETTERS),collapse="")) }\cr
#' To get the numeric equivalent of raw, use\cr
#' \code{ num <- as.numeric(raw) }.\cr
#' To recover the original characters, use\cr
#' \code{ char <- rawToChar( as.raw(num) ) }.\cr
#'
#' @examples
#' # A string consisting of single and multi byte characters
#' # The 3rd, 6th and 7th characters are uppercase Zenkaku Romans.
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nza <- c(97, 98, 239, 188, 163, 100, 101, 239, 188, 166, 239, 188, 167, 104)
#' else
#'  nza <- c(97,98,130,98,100,101,130,101,130,102,104)}
#' za <- rawToChar(as.raw(nza))
#' # za <- num2char(nza)
#'
#' # location of the multi byte characters
#' nchar(za)
#' is.DBCS(za)
#' printm( nchar(za), length(charToRaw(za)), nchar2(za) )
#' printm(unlist(strsplit(za,"")),nbyte(za),is.DBCS(za))
#'
#'
#' @return A number or a numeric vector.
#'
#' @export
#'

nchar2 <- function( x ){
 # # of characters using bytes, not characters, as the unit
 # Shin-ichi Mayekawa
 # 20171011
 # vector x: 20220812cot
 #
 return( sapply(lapply(x,charToRaw),length) )

} # end of nchar2


#' Starting and Ending Columns of Each Character in a Text File
#'
#' @param x A string vector
#'
#' @details
#' This function can be used to get the substring of a string
#' by specifying the starting and the ending columns. \cr
#' It is assumed that the double or triple byte characters takes two columns
#' of a text file.  (Zenkaku Character)
#'
#' If \code{x} contains a string consisting of single and multibyte characters,
#' \preformatted{
#'  ft <- cchar(x)
#'  substr( x, which(ft[,1] == start), To=which(ft[,2] == stop) )
#' }
#' will return the characters between columns \code{start} and \code{stop}.
#'
#' @examples
#' # A string consisting of single and multi byte characters
#' # The 3rd, 6th and 7th characters are uppercase Zenkaku Romans.
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nza <- c(97, 98, 239, 188, 163, 100, 101, 239, 188, 166, 239, 188, 167, 104)
#' else
#'  nza <- c(97,98,130,98,100,101,130,101,130,102,104)}
#' za <- rawToChar(as.raw(nza))
#' # za <- num2char(nza)
#'
#' # location of the multi byte characters
#' nchar(za)
#' is.DBCS(za)
#' printm( nchar(za), nchar2(za), nchar(za)+sum(is.DBCS(za)) )
#' printm(1:nchar(za), unlist(strsplit(za,"")),nbyte(za),cchar(za))
#'
#' # When input is a string vector
#' cchar(c(za,za))
#'
#' # convert column position to character position
#' # from and to as column position
#' from <- c(1,2,3,5,6,7,9,11)
#' to <- c(1,2,4,5,6,8,10,11)
#' # character position corresponding to (from,to) to be used in substr(ing)
#' FTc <- cchar(za,from,to)[[1]]
#' # substrings
#' ssg <- substring(za,FTc[,1],FTc[,2])
#' # substrings using substr2 which can hadle column (from,to)
#' ss2 <- substr2(za,from,to)
#' za1 <- strsplit(za,"")[[1]]   # to print each character
#' printm(za1, from, to, FTc, ssg,ss2)
#'
#' # use of last option
#' cchar( za, 1:11, 1:11 )
#' cchar( za, 1:11, 1:11, last=0 )
#'
#' cchar( za, 3,4 )
#' cchar( za, 3,5 )
#' cchar( za, 3,7 )
#' cchar( za, 3,7, last=0 )
#'
#' # When input is a string vector
#' cchar( c(za,za), 1:11, 1:11, last=0 )
#'
#'
#' @return
#' When \code{from} is not given, a list of matrices
#' \code{FT[[i]]} where \code{FTT[[i]][j,1]} and \code{FTT[[i]][j,2]},
#' resp, are the starting and ending columns of the \code{j}-th character
#' of the \code{i}-th string.
#' When the input is a string, \code{FT[[1]]} will be returned.
#' \cr
#' When \code{from} is given, a list of matrices
#' \code{FTc[[i]]} corresponding to each of the strings where
#' \code{FTc[[i]][j,1], FTc[[i]][j,2]} are, resp,
#' the starting and ending characters corresponding to
#' \code{from[j]} and \code{to[j]} of the i-th string.
#'
#' @export
#'

cchar <- function( x, from=NULL, to=NULL, last=TRUE  ){
 # starting and ending columns of each character in a string vector
 # Shin-ichi Mayekawa
 # 20220811cot,14,19,
 # nchar with width: 20220821
 # start,stop, res -> from,to, FT: 20220821
 # convert_code included: 20220821
 # new method: 20220910cot
 #

 FT=lapply(x, function(lin){
  nb2=sapply(strsplit(lin,""),nchar,type="width")
  to=cumsum(nb2)  # ending column of each character
  from=to - nb2 + 1 # starting column of each character
  ft=cbind(from,to)
  colnames(ft)=c("from","to")
  return(ft)
 })

 if( is.null(from) ){
  if( length(FT) == 1 ) FT=FT[[1]]
  return( FT )
 }

 #
 # old convert_column starts here.
 #

 lenx=length(x)
 FT2=vector(mode="list", length=lenx)
 for( i in 1:lenx){
  ft=FT[[i]]

  # old method
  # lfrom=length(from)
  # FTnew=matrix(NA,lfrom,2)
  # for( j in 1:lfrom ){
  #  loc=which(ft[,1] == from[j])
  #  if(length(loc) > 0 ) FTnew[j,1]=loc
  #  loc=which(ft[,2] == to[j])
  #  if(length(loc) > 0 ) FTnew[j,2]=loc
  #  else if( last ) FTnew[j,2]=nchar(x[i])
  # }
  # end of old method

  # new
  FTbigF=rep(NA,nchar(x[i],type="width"))
  FTbigT=FTbigF
  FTbigF[ft[,1]]=1:nrow(ft)
  FTbigT[ft[,2]]=1:nrow(ft)

  FTnew=cbind(FTbigF[from],FTbigT[to])
  if( last ) FTnew[is.na(FTnew[,2]),2]=nchar(x[i])

  FT2[[i]]=FTnew
 }

 # if( lintext == 1 ) FT2=FT2[[1]]
 return( FT2 )

} # end of cchar







#' Substring Using Column Location as the Unit.
#'
#' @param x A string vector
#' @param from The first column (location in a line of a text file)
#' @param to The last column or 0 meaning the end of string
#' @param strict = 1 to check if start and stop are valid.
#' @param trim  = 1 to trim the result by lazy.tools::trim
#' @param ... options for lazy.tools::trim
#'
#' @details
#' It is assumed that the double or triple byte character takes two colums
#' of a text file.  (Zenkaku Character) \cr
#' See the description of \code{cchar}.
#'
#' When scrict=1, if the start or stop value is invalid, NA will be returned.\cr
#' When strict=0, if the start value is valid and the stop value is invalid,
#' stop will be set to the location of the last character.
#'
#' When trim is used, the result will be re-encoded to UTF-8.
#'
#' @examples
#'
#' # A string consisting of single and multi byte characters
#' # The 3rd, 6th and 7th characters are uppercase Zenkaku Romans.
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nza <- c(97, 98, 239, 188, 163, 100, 101, 239, 188, 166, 239, 188, 167, 104)
#' else
#'  nza <- c(97,98,130,98,100,101,130,101,130,102,104)}
#' za <- rawToChar(as.raw(nza))
#' # za <- num2char(nza)
#'
#' printm(za)
#' # location of the multi byte characters
#' is.DBCS(za)
#' printm( nchar(za), nchar2(za), nchar(za)+sum(is.DBCS(za)) )
#' printm(unlist(strsplit(za,"")),nbyte(za),cchar(za))
#' # The first to the fourth characters
#' substr(za,1,4)
#' # The characters of za in the first to the fourth column.
#' substr2(za,1,4)
#'
#'
#' # Another example
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nn <- c(87, 101,  32, 104,  97, 118, 101,  32, 228, 184, 141, 232, 184
#'         , 176, 231, 159, 169,  32, 121, 101, 116,  33)
#' else
#'  nn <- c(87, 101,  32, 104,  97, 118, 101,  32, 149, 115, 230, 250, 139
#'          , 233, 32, 121, 101, 116,  33)}
#' za2=num2char(nn)
#' printm( nchar(za2), nchar2(za2), nchar(za2)+sum(is.DBCS(za2)) )
#' printm(1:nchar(za2),unlist(strsplit(za2,"")),nbyte(za2),cchar(za2))
#'
#' # Note that start and stop must be the numbers contained in, resp,
#' # the first and the second columns of the returning matrix from
#' # cchar function.
#' substr2(za2,4,7)    # ok
#' substr2(za2,4,9)    # NG
#' substr2(za2,4,10)   # ok
#' substr2(za2,4,11)   # NG
#' substr2(za2,4,12)   # ok
#' substr2(za2,4,9, strict=1)    # NG
#' substr2(za2,4,11, strict=1)   # NG
#' substr2(za2,9,10, strict=1)   # ok
#' substr2(za2,9,11, strict=1)   # NG
#'
#'
#'
#'
#' # reading Shift-JIS files on from R.4.1.3
#' nobs <- 10
#' infile1 <- system.file("TestData1.txt",package="lazy.tools")
#' if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 ){
#'  temp1 <- ReadLines(infile1, n=nobs+2)[-(1:2)]
#' } else{
#'  # The result will be Double Byte.
#'  temp1 <- ReadLines(infile1, n=nobs+2, asDB=1)[-(1:2)]
#'  # The result will be Triple Byte.
#'  temp11 <- ReadLines(infile1, n=nobs+2)[-(1:2)]
#'
#'  nbyte(temp1)
#'  nbyte(temp11)
#'  identical(temp1[-nobs],temp11[-nobs])  # true
#'  identical(nbyte(temp1[-nobs]),nbyte(temp11[-nobs])) # false
#' }
#'
#' # reading UTF-8
#' nobs <- 10
#' infile2 <- system.file("TestData2.txt",package="lazy.tools")
#' temp2 <- ReadLines(infile2, n=nobs+2, encoding="UTF-8")[-(1:2)]
#' nbyte(temp2)
#'
#' # starting and ending columns of each field
#' from=c(1, 7,25,26,27,28,29,30,31,32,34)
#' to=c(  5,23,25,26,27,28,29,30,31,32,39)
#'
#' # character locations corresponding to from and to: should be equal.
#' FTc1=cchar( temp1, from, to )
#' FTc2=cchar( temp2, from, to )
#' char=strsplit(temp1[1],"")[[1]]
#' printm( char, from,to, FTc1[[1]],FTc2[[1]] )
#'
#' # substringing using FTc
#' substring( temp2[1], FTc1[[1]][,1], FTc2[[1]][,2] )
#' substring( temp2[2], FTc1[[2]][,1], FTc2[[2]][,2] )
#'
#' # get the field values as substrings  using substr2 function
#' s12=substr2(temp1,from[2],to[2])
#' s14=substr2(temp1,from[4],to[4])
#' s111=substr2(temp1,from[11],to[11])
#' s22=substr2(temp2,from[2],to[2])
#' s24=substr2(temp2,from[4],to[4])
#' s211=substr2(temp2,from[11],to[11])
#'
#' # comparison
#' printm(s14,s24)
#'
#' # Note that s111 and s211 are trimmed because they come from
#' # the variable length last columns.
#' # (On R4.1.3  s21 and s11 cannot be printmed together by printm.)
#' print.listof(list(s12=s12,s22=s22,s111=s111,s211=s211))
#'
#' # On R4.1.3,
#' # substr or substr2 does not change the encoding.
#' # lazy.tools::trim changes the encoding.
#' # s12t=trim(s12)
#' # printm( s12[1], s12t[1] )
#' # printm( nbyte(s12[1]),nbyte(s12t[1]) )
#' # This does not.
#' # s12tt=substr(s12,1,nchar(trim(s12)))
#' # printm(s12[1],s12tt[1])
#' # printm(nbyte(s12[1]),nbyte(s12tt[1]))
#'
#'
#' @return A vector consisting of the substrings of the input vector.
#' The result will be a list if the input is a string vector.
#'
#' @export
#'

substr2 <- function( x, from, to=0, strict=0, trim=0, ... ){
 # substr using bytes, not characters, as the unit
 # Shin-ichi Mayekawa
 # 20170701,02,03
 # comments: 20181101dnc
 # UTF-8: 20220811cot
 # strict: 20220813cot
 # new method: 20220821
 # start,stop -> from,to: 20220821
 # convert_code -> cchar: 20220821
 # trim: 20220821
 # roxygen2: 20220823
 #

 #  convert (from,to) to FTc
 if( strict )
   FTc=cchar( x, from, to, last=0 )
 else
   FTc=cchar( x, from, to, last=1 )

 # use substring which can handle vector start and stop
 res=mapply( function(y,ftc){ substring(y,ftc[,1],ftc[,2]) }, x, FTc
             , SIMPLIFY=FALSE )
 names(res)=names(x)

 if( length(x) == 1 ) res=res[[1]]
 if( length(from) == 1 ) res=unlist(res)

 if( trim ){
  res=trim(res,...)
 }
 return( res )

} # end of substr2



#' Checks if the Characters in a String are Multi Byte Characters.
#'
#' @param x String vector
#'
#' @details
#' Locale of your Windows machine can be obtained by the following:
#' \preformatted{
#' shell("ver")
#' shell("PowerShell  Get-WinSystemLocale")
#' shell("chcp > chcp.txt")  # chcp.txt will be created somewhere.
#' strsplit(readLines("chcp.txt")," ")[[1]][3]
#' }
#' Code 923 means Shift-JIS.
#'
#' Version and locale of R can be obtained as follows;
#' \preformatted{
#' version
#' Sys.getlocale()
#' }
#' \cr
#' T check the character encoding, use: \code{Encoding(char)}.
#' The result will be UTF-8 or unknown meaning system encoding.
#' \cr
#'
#' About rawToChar and charToRaw functions: \cr
#' To get the raw expression of character, use\cr
#'  \code{ char <- paste(c(0:9," ",letters,LETTERS),collapse="")}
#'  \code{ raw <- charToRaw(char) }\cr
#' To get the numeric equivalent of raw, use\cr
#'  \code{ num <- as.numeric(raw) }.\cr
#' To recover the original characters, use\cr
#'  \code{ char <- rawToChar( as.raw(num) ) }.\cr
#' \cr
#' Hex numbers used to express raw expression can be bypassed by using \cr
#'  \code{num <- char2num(char)} \cr
#'  \code{char <- num2char(num)} \cr
#'
#' @examples
#'
#' # A string consisting of single and multi byte characters
#' # The 3rd, 6th and 7th characters are uppercase Zenkaku Romans.
#' {if( regexpr("utf8",Sys.getlocale (category = "LC_CTYPE")) > 0 )
#'  nza=c(97, 98, 239, 188, 163, 100, 101, 239, 188, 166, 239, 188, 167, 104)
#' else
#'  nza <- c(97,98,130,98,100,101,130,101,130,102,104)}
#' za <- rawToChar(as.raw(nza))
#' # za <- num2char(nza)
#'
#' # location of the multi byte characters in a string
#' is.DBCS(za)
#'
#' # Pick up the single byte characters.
#' strsplit(za,"")[[1]][!is.DBCS(za)]
#' # Pick up the multi byte characters.
#' strsplit(za,"")[[1]][is.DBCS(za)]
#'
#' # strsplit changes the encoding from Shift-JIS (double byte) to UTF-8.
#' Encoding(strsplit(za,"")[[1]])
#' Encoding(substring(za,1:nchar(za),1:nchar(za)))
#' unlist(nbyte(strsplit(za,"")[[1]]))
#' unlist(nbyte(substring(za,1:nchar(za),1:nchar(za))))
#'
#'
#' @return A logical vector or list of logical vectors indicating if
#' each character in the input string vector is a multi byte chractor or not.
#'
#' @export
#'

is.DBCS <- function( x ){
 # Checks if the Characters in a String are Multi Byte Characters
 # Shin-ichi Mayekawa
 # 20170703
 # ==2 -> > 1: 20220811cot
 # roxygen2 example: 20220812cot,22
 #

 loc=lapply( strsplit(x,"")
             , function(y) unlist(lapply(lapply(y,charToRaw),length)) > 1 )
 if( length(loc) == 1 ) loc=unlist(loc)
 return( loc  )
} # end of is.DBCS


#' @rdname is.DBCS
#' @export
#'

is.MBCS <- is.DBCS



#' Substr Using Column Location as the Unit.
#'
#' @param x A string vector
#' @param start The first location
#' @param stop The last location
#'
#' @details
#'
#' This is for strictly DUOBLE byte characters. NOT for UTF-8 characters.
#' For strictly double byte characters, this is faster than susbtr2.
#'
#' About rawToChar and charToRaw functions: \cr
#' To get the raw expression of a string, use\cr
#' \code{ raw <- charToRaw(paste(c(0:9," ",letters,LETTERS),collapse="")) }\cr
#' To get the numeric equivalent of a raw (vector),  use\cr
#' \code{ num <- as.numeric(raw) }.\cr
#' To recover the original string, use\cr
#' \code{ char <- rawToChar( as.raw(num) ) }.\cr
#'
#' \cr
#' If the n-th byte is the beginning or the ending location of \cr
#' a double byte character, \code{substrDBCS(x,n,n)} is invalid.\cr
#' Consult \code{is.DBCS(x)} and use with caution.
#'
#' @examples
#' # The exa,ple below causes error on R 4.2.0 and above.
#' \dontrun{
#' # A string consisting of single and double byte characters
#' nza <- c(97,98,130,131,100,101,130,134,130,135,104)
#' za <- rawToChar(as.raw(nza))
#' Print(za)
#' # location of the double byte characters
#' is.DBCS(za)
#' # The first to the fourth characters
#' substr(za,1,4)
#' # The characters stored in the first to the fourth bytes of za.
#' substrDBCS(za,1,4)
#' }
#'
#' @return A vector consisting of the substrings of the input vector.
#'
#' @export
#'

substrDBCS <- function( x, start, stop=max(nchar(x,type="byte")) ){
  # substr using bytes, not characters, as the unit
  # Shin-ichi Mayekawa
  # 20170701,02,03
  # comments: 20181101dnc
  # substrDBCS renamed as substrDBCS
  #

  # Raw=charToRaw(x)
  # Char=rawToChar(Raw[start,stop])

  if( start > stop ) return( "" )
  unlist( lapply( lapply( lapply(x,charToRaw), "[", start:stop ), rawToChar ) )

 } # substrDBCS



