R/si2f.R

Defines functions si2f

Documented in si2f

#' Inverse of [sitools::f2si()]
#'
#' @param string A character vector representing numbers along with SI
#'     prefixes and possibly a unit.
#' @param unit The unit to expect after the SI prefix, if any.
#' @return A numeric vector containing the values parsed from
#'     `string`.
#' @examples
#' # convert single number
#' si2f("10k")
#'
#' # convert single number with unit
#' si2f("23 mV", unit = "V")
#'
#' # convert list of numbers
#' si_strings <- c("100 k", "35 E", "4 m")
#' si2f(si_strings)
#'
#' @export
si2f <- function(string, unit = "") {
    req_ns("rex")

    if (length(string) == 0) {
        return(numeric(0))
    }
    sifactor <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06,
                  0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21,
                  1e+24)
    pre <- c("y", "z", "a", "f", "p", "n", "u", "m",
             "", "k", "M", "G", "T", "P", "E", "Z", "Y")

    rx <- rex::rex(
        ## Leading whitespace
        start,
        zero_or_more(space),

        ## Capture a floating point number
        capture(
            ## Sign
            maybe(one_of("+", "-")),
            ## Integer part
            zero_or_more(digit),
            ## Decimal point
            maybe("."),
            ## Fractional part (or integer part when decimal is not
            ## present)
            one_or_more(digit),
            ## Exponential notation
            maybe(
                one_of("e", "E"),
                maybe(one_of("+", "-")),
                one_or_more(digit)
            )
        ),

        ## Space between number and unit
        zero_or_more(space),

        ## Capture SI prefix
        capture(maybe(one_of(pre))),

        unit,

        ## Trailing whitespace
        zero_or_more(space),
        end
    )

    m <- str_match(string, rx)
    base <- as.numeric(m[,2])
    p <- m[,3]
    fac <- sifactor[match(p, pre)]
    base * fac
}

# This is needed because sitools::f2si(0) is broken.

#' @importFrom glue glue
f2si_internal <- function (number, unit = "")
{
    sifactor <- c(-Inf, 1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06,
        0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21,
        1e+24)
    pre <- c("", "y", "z", "a", "f", "p", "n", "u", "m",
             "", "k", "M", "G", "T", "P", "E", "Z", "Y")
    ix <- findInterval(abs(number), sifactor)
    if (length(ix) > 0) {
        sistring <- glue("{number/sifactor[ix]} {pre[ix]}{unit}") %>% str_trim("right")
    }
    else {
        sistring <- as.character(number)
    }
    return(sistring)
}
DarwinAwardWinner/rctutils documentation built on July 22, 2022, 5:19 a.m.