1#' Split a string at linebreaks. 2#' 3#' Return a list of the lines in the string, breaking at line boundaries. 4#' 5#' Line breaks are not included in the resulting list unless \code{keepends} is 6#' \code{TRUE}. Line breaks include \code{"\n"}, \code{"\r"}, and \code{"\r\n"}. 7#' 8#' @param str A character vector. 9#' @param keepends A logical vector. 10#' 11#' @return A list of character vectors. 12#' 13#' @references \url{https://docs.python.org/3/library/stdtypes.html#str.splitlines} 14#' 15#' @seealso \code{\link{pystr_split}} 16#' 17#' @examples 18#' pystr_splitlines("First\nSecond\rThird\r\n") 19#' pystr_splitlines("First\nSecond\rThird\r\n", TRUE) 20#' 21#' @export 22pystr_splitlines <- function(str, keepends=FALSE) { 23 return(mapply(pystr_splitlines_, str, keepends, SIMPLIFY=FALSE, USE.NAMES=FALSE)) 24} 25 26pystr_splitlines_ <- function(str, keepends) { 27 linebreaks = c("\r\n", "\r", "\n") 28 splits = c() 29 remaining = str 30 31 repeat { 32 if(remaining == "") { 33 return(splits) 34 } 35 36 idx = sapply(linebreaks, function(x) pystr_find(remaining, x)) 37 38 if(all(idx < 0)) { 39 return(c(splits, remaining)) 40 } 41 42 idx = idx[sapply(idx, function(x) x > 0)] 43 44 if(!is.na(idx["\r\n"]) && idx["\r\n"] == min(idx)) { 45 parts = pystr_partition(remaining, "\r\n")[[1]] 46 } else { 47 parts = pystr_partition(remaining, names(sort(idx)[1]))[[1]] 48 } 49 50 if(keepends) { 51 splits = c(splits, paste0(parts[1], parts[2])) 52 } else { 53 splits = c(splits, parts[1]) 54 } 55 56 remaining = parts[3] 57 } 58} 59