rr-markdownknitrkablekableextra

KableExtra adding linebreaks in columns with long nonwhitespace strings


I have a long string which I want in a table, for instance 100x the letter A (AAA...). I would like kable to split this string into multiple lines if they don't fit in the table instead of making these strings overflow such as shown here.

I noticed kable is actually able of doing so, provided there are newlines or -'s in your string, see for instance here.

However, I would like kable to do this splitting on either selected characters or on any character, so the output result would be this, but I don't know how to achieve this. I had a look on SO and in the kableextra documentation, but no luck. Any suggestions?

Below is a chunk to play around with.

---
title: 'rasstasrt'
sansfont: Calibri Light
output: pdf_document
---

```{r setup, include=FALSE}
library(kableExtra);
library(dplyr)
knitr::opts_chunk$set(cache = F)
```


```{r}
dt <-tibble(Items =c("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaAAa", "Item 2", "Item 3"),
            Tmd5ext_1 =c("Lorem ipsum  "),
            Text_2 =c("Duis pos "))

kableExtra::kable(dt, "latex", booktabs = F, col.names =c("Item", "Short Title", "Veryong Title"))  %>% column_spec(1:3, width = "5cm", )
```

Solution

  • You can leverage the newline character in latex, \\ and the argument escape = FALSE in kableExtra::kable(). Settting escape = FALSE causes the \\ to be read as newline characters instead of literal \\. Note that because \ is an escape character in R, you need two slashes \\ in order for R to interpret a single slash \, so to get 2 literal slashes \\ you need to put 4 \\\\ in the string.

    ---
    title: 'rasstasrt'
    sansfont: Calibri Light
    output: pdf_document
    ---
    
    ```{r setup, include=FALSE}
    library(kableExtra)
    library(dplyr)
    knitr::opts_chunk$set(cache = F)
    ```
    
    
    ```{r}
    
    dt <-tibble(Items = c("AAAAAAAAAAAAAAA\\\\AAAAAAAAAA\\\\AAAAAAAAAAA\\\\AAAAAAAAAAAAA\\\\AAAAAAaaaaAAa", 
                          "Item 2", 
                          "Item 3"),
                Tmd5ext_1 = c("Lorem ipsum  "),
                Text_2 = c("Duis pos "))
    
    kableExtra::kable(dt, 
                      "latex", 
                      booktabs = F, 
                      col.names =c("Item", "Short Title", "Veryong Title"), 
                      escape = FALSE)  %>% 
      column_spec(1:3, width = "5cm")
    ```
    

    enter image description here

    Alternatively, if you wanted to insert the newline after a specific number of characters, you could write a function to do that.

    ---
    title: 'rasstasrt'
    sansfont: Calibri Light
    output: pdf_document
    ---
    
    ```{r setup, include=FALSE}
    library(kableExtra)
    library(dplyr)
    knitr::opts_chunk$set(cache = F)
    ```
    
    
    ```{r}
    add_return <- function(x, len) {
      # intialize empty vector
      y <- c()
    
      # start at beginning of string
      i <- 1
    
      # Break string up into lengths of len
      while(i < nchar(x)) {
    
        y <- c(y,substr(x, i, i + len - 1))
    
        i <- i + len
    
      }
    
      # concatenate the substrings together with the newline characters
      paste0(y, collapse = "\\\\") 
    
    }
    
    dt <-
      tibble(
        Items = c(
          add_return(
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaAAa",
           len = 5
          ),
          "Item 2",
          "Item 3"
        ),
        Tmd5ext_1 = c("Lorem ipsum  "),
        Text_2 = c("Duis pos ")
      )
    
    kableExtra::kable(
      dt,
      "latex",
      booktabs = F,
      col.names = c("Item", "Short Title", "Veryong Title"),
      escape = FALSE
    )  %>% column_spec(1:3, width = "5cm")
    ```
    

    enter image description here

    You could also use regular expressions to insert the return after a specific character string.

    ---
    title: 'rasstasrt'
    sansfont: Calibri Light
    output: pdf_document
    ---
    
    ```{r setup, include=FALSE}
    library(kableExtra)
    library(dplyr)
    knitr::opts_chunk$set(cache = F)
    ```
    
    
    ```{r}
    regex_add_return <- function(x, after) {
    
      gsub(pattern = paste0("(",after,")"), replacement = paste0("\\1\\\\\\\\"),x)
    
    }
    
    dt <-
      tibble(
        Items = c(
          regex_add_return(
            "AAAAAAAAAAAAAAAz123AAAAAAAAAAAAAAAz123AAAAAAAAAAz123AAAAAAAAAAAAAAAaaaaAAa",
            after = "z123"
          ),
          "Item 2",
          "Item 3"
        ),
        Tmd5ext_1 = c("Lorem ipsum  "),
        Text_2 = c("Duis pos ")
      )
    
    kableExtra::kable(
      dt,
      "latex",
      booktabs = F,
      col.names = c("Item", "Short Title", "Veryong Title"),
      escape = FALSE
    )  %>% column_spec(1:3, width = "5cm")
    ```
    

    enter image description here

    Note that there are 8 slashes in gsub() because the slash is also an escape character for regular expressions, so each literal slash has to be escaped with a slash, but then each slash that is being used as an escape character for regex also has to be escaped again for R, requiring another slash.