Pretty-printing of character strings (ensuring automatic line-breaks to stay within a given print margin)
Asked Answered
P

1

7

I try to stick to a print margin of 80 characters for everything related to character strings, especially concerning custom-made messages (warnings, errors etc.)

Now, I always wondered if there's an easy way to make sure that some print margin restrictions are automatically ensured/enforced, e.g. that a given atomic string is automatically broken down into a vector of character strings in case it exceeds the chosen print margin. I've googled a bit but didn't really find anything that fits my needs.

Question

Did someone come up with a nice "pretty-printing" function yet that I could further build upon?.


This is what I came up with myself so far:

Function def

makePretty <- function(
    string,
    print.margin=80,
    ...
){
    out <- string
    if (nchar(string) > print.margin) {
        times       <- ceiling(nchar(string)/print.margin)
        breaks      <- rep(print.margin+1, times)
        breaks      <- cumsum(breaks)
        string.spl  <- unlist(strsplit(string, split=" "))
        seps        <- str_locate_all(string, " ")[[1]][,"start"]
        queue       <- NA

        envir <- environment()
        out <- unlist(sapply(1:length(breaks), function(ii) {
            idx.next    <- breaks[ii]
            if (ii < length(breaks)) {
                idx <- which(seps <= idx.next)
                chunk <- string.spl[idx]
                envir$string.spl   <- envir$string.spl[-idx]
                envir$seps      <- envir$seps[-idx]       
            } else {
                chunk <- string.spl
            }
            chunk <- paste(chunk, collapse=" ")
            # Chunk could exceed print margin in case the right hand neighbor
            # wasn't a blank >> check again 
            if (nchar(chunk) > print.margin) {
                chunk <- makePretty(string=chunk, print.margin=print.margin)
                envir$queue <- chunk[length(chunk)]
                chunk <- chunk[-length(chunk)]
            } else {
                if (!is.na(envir$queue)) {
                    # Prepend chunk with queued chunk
                    chunk <- paste(envir$queue, chunk, sep=" ")
                    # Reset queue
                    envir$queue <- NA
                }
            }
            # /
            out <- chunk
            return(out)
        })) 
    }
    return(out)
}

Function Application

string <- "This is just an example of a very long character string that exceeds the default print margin of 80 and therefore needs some pretty printing. In fact it's so long that it needs to be broken down into three parts."
> makePretty(string=string)
[1] "This is just an example of a very long character string that exceeds the default"
[2] "print margin of 80 and therefore needs some pretty printing. In fact it's so"    
[3] "long that it needs to be broken down into three parts."      

> string <- "This is just an example of a very long character string that exceeds a certain print margin and therefore needs some pretty printing. In fact it's so long that it needs to be broken down into numerous parts."
> makePretty(string=string, print.margin=40)
[1] "This is just an example of a very long"       
[2] "character string that exceeds a certain"      
[3] "print margin and therefore needs some"        
[4] "pretty printing. In fact it's so long"        
[5] "that it needs to be broken down into numerous"
[6] "parts."    

string <- "This is just an example of a very long character string that exceeds the default print margin of 80 and therefore needs some pretty printing. In fact it's so looooooooooooooooooooooooooooooooong that it needs to be broken down into four parts."
> makePretty(string=string)
[1] "This is just an example of a very long character string that exceeds the default"
[2] "print margin of 80 and therefore needs some pretty printing. In fact it's so"    
[3] "looooooooooooooooooooooooooooooooong that it needs to be broken down into four"  
[4] "parts." 

string <- "This is just an example of a very long character string that exceeds the default print margin of 80 and therefore needs some pretty printing. In fact it's soooooooo looooooooooooooooooooooooooooooooong that it needs to be broken down into four parts."
> makePretty(string=string)
[1] "This is just an example of a very long character string that exceeds the default"
[2] "print margin of 80 and therefore needs some pretty printing. In fact it's"       
[3] "soooooooo looooooooooooooooooooooooooooooooong that it needs to be broken down"  
[4] "into four parts."

So far, the approach solely relies on blank spaces to determine which words belong together - which is probably not covering other "real world scenarios" such as colons, semi-colons etc.

Potation answered 28/8, 2012 at 13:54 Comment(0)
I
17

The base R function strwrap seems to do exactly what you describe:

strwrap(x, width=80)
[1] "This is just an example of a very long character string that exceeds the"    
[2] "default print margin of 80 and therefore needs some pretty printing. In fact"
[3] "it's so long that it needs to be broken down into three parts."              

strwrap(x, 40)
[1] "This is just an example of a very long" "character string that exceeds the"     
[3] "default print margin of 80 and"         "therefore needs some pretty printing." 
[5] "In fact it's so long that it needs to"  "be broken down into three parts."

And you can use paste with the argument collapse="\n" to combine the pieces into a single string with newlines:

cat(paste(strwrap(x, 40), collapse="\n"))
This is just an example of a very long
character string that exceeds the
default print margin of 80 and
therefore needs some pretty printing.
In fact it's so long that it needs to
be broken down into three parts.
Impunity answered 28/8, 2012 at 13:58 Comment(1)
Great answer, makes things so much easier when producing long stringsGarrity

© 2022 - 2024 — McMap. All rights reserved.