🔍 An RStudio addin slash regex utility belt
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

201 lines
5.7KB

  1. #' RegExplain gadget
  2. #'
  3. #' The function behind the RegExplain Selection and RegExplain File
  4. #' addins. Opens the RegExplain gadget interface in an RStudio viewer
  5. #' pane.
  6. #'
  7. #' @examples
  8. #' \dontrun{
  9. #' regexplain_gadget(text = month.name, pattern = "(Ma|Ju)|(er)")
  10. #' regexplain_web(text = month.name, pattern = "(Ma|Ju)|(er)")
  11. #' regexplain_file()
  12. #' }
  13. #'
  14. #' @import miniUI
  15. #' @import shiny
  16. #' @param text Text to explore in gadget (editable using interface)
  17. #' @param pattern Regular Expression to edit or visualize using RegExplain
  18. #' @param start_page Open gadget to this tab, one of `"Text"`, `"RegEx"`,
  19. #' `"Output"`, or `"Help"`
  20. #' @export
  21. regexplain_gadget <- function(
  22. text = NULL,
  23. pattern = NULL,
  24. start_page = if (is.null(text)) "Text" else "RegEx"
  25. ) {
  26. stopifnot(requireNamespace("miniUI"), requireNamespace("shiny"))
  27. viewer <- shiny::paneViewer(minHeight = 800)
  28. runGadget(
  29. regexplain_gadget_ui(text, pattern, start_page),
  30. regexplain_gadget_server(check_version()),
  31. viewer = viewer
  32. )
  33. }
  34. #' @describeIn regexplain_gadget Launches the RegExplain gadget in a browser or an
  35. #' RStduio viewer pane.
  36. #' @inheritDotParams shiny::shinyApp
  37. #' @export
  38. regexplain_web <- function(text = NULL, pattern = NULL, start_page = "Text", ...) {
  39. stopifnot(requireNamespace("miniUI"), requireNamespace("shiny"))
  40. shinyApp(
  41. regexplain_gadget_ui(text, pattern, start_page),
  42. regexplain_gadget_server(check_version()),
  43. ...
  44. )
  45. }
  46. # ---- Gadget Helper Functions and Variables ----
  47. sanitize_text_input <- function(x) {
  48. if (is.null(x) || !nchar(x)) {
  49. return(x)
  50. }
  51. rx_unicode <- "\\\\u[0-9a-f]{4,8}"
  52. rx_hex <- "\\\\x[0-9a-f]{2}|\\\\x\\{[0-9a-f]{1,6}\\}"
  53. rx_octal <- "\\\\[0][0-7]{1,3}"
  54. rx_escape <- paste(rx_unicode, rx_hex, rx_octal, sep = "|")
  55. if (grepl(rx_escape, x, ignore.case = TRUE)) {
  56. try(
  57. {
  58. y <- stringi::stri_unescape_unicode(x)
  59. },
  60. silent = TRUE
  61. )
  62. if (!is.na(y)) x <- y
  63. }
  64. # x <- gsub("\u201C|\u201D", '"', x)
  65. # x <- gsub("\u2018|\u2019", "'", x)
  66. x
  67. }
  68. toHTML <- function(...) {
  69. x <- paste(..., collapse = "")
  70. x <- gsub("\n", "\\\\n", x)
  71. x <- gsub("\t", "\\\\t", x)
  72. x <- gsub("\r", "\\\\r", x)
  73. HTML(x)
  74. }
  75. regexFn_choices <- list(
  76. "Choose a function" = "",
  77. base = c(
  78. "grep",
  79. "grepl",
  80. "sub", #<<
  81. "gsub", #<<
  82. "regexpr",
  83. "gregexpr",
  84. "regexec"
  85. ),
  86. stringr = c(
  87. "str_detect",
  88. "str_locate",
  89. "str_locate_all",
  90. "str_extract",
  91. "str_extract_all",
  92. "str_match",
  93. "str_match_all",
  94. "str_replace", #<<
  95. "str_replace_all", #<<
  96. "str_split"
  97. ),
  98. "rematch2" = c(
  99. "re_match",
  100. "re_match_all",
  101. "re_exec",
  102. "re_exec_all"
  103. )
  104. )
  105. regexFn_substitute <- c(
  106. paste0(c("", "g"), "sub"),
  107. paste0("str_replace", c("", "_all"))
  108. )
  109. get_pkg_namespace <- function(fn) {
  110. x <- names(purrr::keep(regexFn_choices, ~ (fn %in% .)))
  111. if (length(x) > 1) warning(fn, " matches multiple functions in regexFn_choices, please review.")
  112. x
  113. }
  114. #' Check if an updated version is available
  115. #'
  116. #' I included this because it can be difficult to tell if your RStudio Addins
  117. #' are up to date. I may add new features that you want but you won't hear about
  118. #' the updates. This function checks if an update is available, using GitHub
  119. #' tags. If an update is available, a modal dialog is shown when you start
  120. #' the regexplain gadget. This only happens once per R session, though, so feel
  121. #' free to ignore the message.
  122. #'
  123. #' @param gh_user GitHub user account
  124. #' @param gh_repo GitHub repo name
  125. #' @param this_version The currently installed version of the package
  126. #' @keywords internal
  127. check_version <- function(
  128. gh_user = "gadenbuie",
  129. gh_repo = "regexplain",
  130. this_version = packageVersion("regexplain")
  131. ) {
  132. ok_to_check <- getOption("regexplain.no.check.version", TRUE)
  133. if (!isTRUE(ok_to_check)) {
  134. return(NULL)
  135. }
  136. if (!requireNamespace("jsonlite", quietly = TRUE)) {
  137. return(NULL)
  138. }
  139. get_json <- purrr::possibly(jsonlite::fromJSON, NULL)
  140. gh_tags <- get_json(
  141. paste0("https://api.github.com/repos/", gh_user, "/", gh_repo, "/git/refs/tags"),
  142. simplifyDataFrame = TRUE
  143. )
  144. if (!is.null(gh_tags)) {
  145. gh_tags$tag <- sub("refs/tags/", "", gh_tags$ref, fixed = TRUE)
  146. gh_tags$version <- sub("^v\\.?", "", gh_tags$tag)
  147. }
  148. if (!is.null(gh_tags) && any(gh_tags$version > this_version)) {
  149. max_version <- max(gh_tags$version)
  150. max_tag <- gh_tags$tag[gh_tags$version == max_version]
  151. options(regexplain.no.check.version = FALSE)
  152. return(
  153. list(
  154. version = max_version,
  155. link = paste("https://github.com", gh_user, gh_repo, "releases/tag", max_tag, sep = "/")
  156. )
  157. )
  158. } else {
  159. return(NULL)
  160. }
  161. }
  162. #' Loads Regex Pattern Library
  163. #'
  164. #' Patterns sourced from [Regex Hub](https://projects.lukehaas.me/regexhub)
  165. #' are available at <https://github.com/lukehaas/RegexHub> and are copyright
  166. #' Luke Haas licensed under the MIT license available at
  167. #' <https://github.com/lukehaas/RegexHub/commit/3ab87b5a4fd2817b42e2e45dcf040d4f0164ea37>.
  168. #' Patterns source from [qdapRegex](https://github.com/trinker/qdapRegex) are
  169. #' copyright Tyler Rinker and Jason Gray, licensed under the GPL-2 license.
  170. #'
  171. #' @keywords internal
  172. get_regex_library <- function() {
  173. if (!requireNamespace("jsonlite", quietly = TRUE)) {
  174. warning("Please install the `jsonlite` package to use template features")
  175. return(NULL)
  176. }
  177. f_patterns <- system.file("extdata", "patterns.json", package = "regexplain")
  178. if (!file.exists(f_patterns)) {
  179. return(NULL)
  180. }
  181. patterns <- jsonlite::fromJSON(
  182. f_patterns,
  183. simplifyVector = FALSE,
  184. simplifyDataFrame = FALSE,
  185. simplifyMatrix = FALSE
  186. )
  187. patterns <- purrr::keep(patterns, ~ .$name != "")
  188. patterns[order(purrr::map_chr(patterns, "name"))]
  189. }