4 min read

The 12 R functions of Xmas pt5/6

R fun at Xmas

R fun at Xmas

Nearly at the end now! If you want to go back and see where we started, check out this post.

Not quite rot13

I confess, I cheated a little with this one. This function has two other functions declared inside it, technically making this ‘the 14 R functions of xmas’. It’s also fine example of how not to design a function.

This function actually implements a variation on the real ROT13, which is a simple substitution cipher that replaces each letter with the letter 13 steps after it in the alphabet, looping back to “a” when you reach “z”. This version is slightly different in that our available characters also include numbers 0-9 as well as the alphabet. Proper ROT13, using just a-z, is interesting in that because there are 26 letters in the English alphabet the same method can be used to encode and decode messages.

Since we are dealing with 36 characters (alphabet + numbers) the sensible thing to do would be to have done ROT18 instead. Then we could use the same process to encode and decode. These functions are supposed to be fun though, not sensible, so instead we’re going to press on regardless!

Not quite ROT13

Not quite ROT13

Doing ROT13 with an extended character set requires that we use a slightly different process to encode and decode our text, hence the two functions declared inside the main function. Ordinarily I’d consider this to be pretty poorly designed and would have done separate rot13_encode and rot13_decode functions, but then I couldn’t pretend that it was all a single function so it’s all combined into a single tangly mess here!

rot13 <- function(text, decode = FALSE){
  all_chars <- "abcdefghijklmnopqrstuvwxyz1234567890"
  split_chars <- strsplit(all_chars, "")[[1]]
  char_wheel <- rep(split_chars, 2)
  encode_text <- function(char){
    lchar <- tolower(char)
    if (!lchar %in% char_wheel){
      lchar
    } else {
      current_position <- which(char_wheel == lchar)[1]
      new_position <- current_position + 13
      char_wheel[new_position]
    }
  }
  decode_text <- function(char){
    lchar <- tolower(char)
    if (!lchar %in% char_wheel){
      lchar
    } else {
      current_position <- which(char_wheel == lchar)[1] + length(split_chars)
      new_position <- current_position - 13
      char_wheel[new_position]
    }
  }
  input_chars <- strsplit(text, "")[[1]]
  if (decode){
    output_chars <- lapply(input_chars, decode_text)
  } else {
    output_chars <- lapply(input_chars, encode_text)
  }
  cat(paste0(output_chars, collapse = ""))
}

To encode text using the function:

> rot13("Hello R users!")
uryy2 5 86r56!

To decode text:

> rot13("uryy2 5 86r56!", decode = TRUE)
hello r users!

The function converts everything to lower case so that we can restrict the scope to just numbers and lower case characters.

Remember, the goal of having this laid out as a single overall function like this was to fit the format of this series of posts. So in effect it was intentionally badly designed.

Some ideas for improvements:

  • Split it out into an encode and decode function
  • Support other offsets as well as 13 - any valid one would work
  • Write a smaller function that just does ‘true’ ROT13 with just a-z
    • Remember that encoding and decoding of true ROT13 can use the same process
  • There are probably better ways of laying this out as a single function
  • Include upper case characters

Awesome Blogdown

Those readers that follow me on twitter or have read my blog before hopefully know that I run a website called ‘Awesome Blogdown’. It’s a collection of links to blogs made using the fantastic blogdown package by Yihui Xie. It’s a great package that wraps the Hugo static website generator and makes it possible to build websites using Rmarkdown.

This function is the first of the series to venture outside of base R. It depends on the jsonlite package which it uses to extract the data that sites behind the Awesome Blogdown site. Once it has that information, we use our old friends sample(), to choose a random blogdown website, and browseURL() to launch the site in the default browser.

awesome_blogdown <- function(){
  url <- "https://awesome-blogdown.com/sites.json"
  a_b_data <- jsonlite::fromJSON(url)
  a_b_index <- sample(1:length(a_b_data$name), 1)
  browseURL(a_b_data$url[a_b_index])
}

There are a lot of great blogs listed on the awesome blogdown site and this function is essentially just a fun way to discover something new amongst the sites listed there.

Ideas for modifications and improvements:

  • Look for other opportunities to discover new blogs, podcasts and websites
  • There might be a similar function coming in tomorrow’s installment ;)

That’s it for today. We’ll be wrapping up the series tomorrow with our final two functions, “sleigh or ISS” and “twelve days”. Until then, keep having fun with your functions!