2

我想用一个\phantom{...}命令替换一串格式化数字中的前导空格,其中...的长度与前导空格的长度相同。我能做的是:

x <- c(1, 1., 0.230, 10.1, 1000, 10000.12)
y <- format(round(x, 2), nsmall=2, big.mark="\\\\,", big.interval=3L)
gsub(" ", "\\\\phantom{ }", y)

但是,我宁愿有一个\phantom{}合适的长度(比如\phantom{ }几个\phantom{ }.

更新

基于 Arun 的解决方案,我构建了这个函数来格式化数字R以在 LaTeX 表格中对齐:

tabAlign <- function(x, nsmall=0L, digits=NULL,
                     flag.before="\\\\phantom{", flag.after="}", embrace="$",
                     big.mark="\\\\,", big.interval=3L, ...)
{
    x <- if(!is.null(digits)) round(x, digits=digits) else x
    x <- format(x, nsmall=nsmall, big.mark=big.mark, big.interval=big.interval, ...)
    x <- sub("^([ ]+)", paste0(flag.before, "\\1", flag.after), x) 
    paste0(embrace, x, embrace) 
}

现在,让我们用它做一些有用的事情。tabAlign(x)给出:

[1] "$\\phantom{       }1.00$" "$\\phantom{       }1.00$"
[3] "$\\phantom{       }0.23$" "$\\phantom{      }10.10$"
[5] "$\\phantom{ }1\\,000.00$" "$10\\,000.12$"           

将此复制并粘贴到 LaTeX 文件中会发现对齐不正确。原因是big.mark。这会保留nchar(big.mark)=3空格(在R字符串中)。但是,在 LaTeX 中,这占用的空间要少得多,因此数字不再完全对齐。因此,理想情况下,该sub()命令必须nchar(big.mark)考虑(对于任何给定的big.mark)。

更新 2

这是另一个更新,现在考虑了来自 DWin 的提示。

tabAlign <- function(x, nsmall=0L, digits=NULL,
                     flag="\\\\phantom{\\1}", embrace="$",
                     big.mark="\\\\,", big.interval=3L, ...)
{
    ## round (if digits is not NULL)
    x <- if(!is.null(digits)) round(x, digits=digits) else x
    ## determine those with/without big.mark (idea from prettyNum())
    y <- format(x, nsmall=nsmall, trim=TRUE)
    y.sp <- strsplit(y, ".", fixed=TRUE)
    B <- sapply(y.sp, `[`, 1L)
    ind.w.big.mark <- grep(paste0("[0-9]{", big.interval+1L, ",}"), B)
    ind.wo.big.mark <- setdiff(1:length(y), ind.w.big.mark)
    ## format the numbers
    x <- format(x, nsmall=nsmall, big.mark=big.mark, big.interval=big.interval, ...)
    ## substitute spaces
    z <- character(l <- length(x))
    n <- nchar(big.mark)
    for(i in seq_len(l)){
        z[i] <- if(i %in% ind.wo.big.mark) sub("^([ ]+)", paste0(flag, big.mark), x[i])
                else sub("^([ ]+)", flag, x[i])
    }
    ## embrace
    paste0(embrace, z, embrace)
}

唯一缺少的部分是不是替换零件\phantom中的所有空格if(),而是替换空格的数量 - n,其中n <- nchar(big.mark)。如何在 中指定sub()

更新 3

这是一个解决方案(但不太优雅......见下文):

tabAlign <- function(x, nsmall=0L, digits=NULL,
                     flag="\\\\phantom{\\1}", embrace="$",
                     big.mark="\\\\,", big.mark2="\\,", big.interval=3L, ...)
{
    ## round (if digits is not NULL)
    x <- if(!is.null(digits)) round(x, digits=digits) else x
    ## determine those with/without big.mark (idea from prettyNum())
    y <- format(x, trim=TRUE)
    y.sp <- strsplit(y, ".", fixed=TRUE)
    B <- sapply(y.sp, `[`, 1L)
    w.big.mark <- grep(paste0("[0-9]{", big.interval+1L, ",}"), B)
    wo.big.mark <- setdiff(1:length(y), w.big.mark)
    ## format the numbers
    x. <- if(length(wo.big.mark) > 0 && length(w.big.mark) > 0) {
        ## format but trim
        y <- format(x, trim=TRUE, nsmall=nsmall, big.mark=big.mark, big.interval=big.interval, ...)
        ## paste big.mark to all numbers without big.mark
        y[wo.big.mark] <- paste0(big.mark2, y[wo.big.mark])
        format(y, justify="right")
    } else { # either all numbers have big.mark or not
        format(x, nsmall=nsmall, big.mark=big.mark, big.interval=big.interval, ...)
    }
    z <- sub("^([ ]+)", flag, x.)
    ## embrace
    paste0(embrace, z, embrace)
}

x <- c(1, 1., 0.230, 10.1, 1000, 10000.12)
tabAlign(x)
tabAlign(x[1:4])
tabAlign(x[5:6])

如果我们只能指定big.mark(而不是指定big.mark2)会更好。

4

1 回答 1

3

这能解决问题吗?最好显示所需的输出(在测试表达式时确保输出)。感谢 DWin 的建议(见评论)。

sub("^([ ]+)", "\\\\phantom{\\1}", y)

(and捕获匹配模式(这)是从字符串开头开始的一堆连续空格),并且可以使用 . 插入捕获的组\\1。如果您有多个括号,则可以插入每个捕获的组,并从 \1 到 \9 进行反向引用。

于 2012-12-28T23:29:01.513 回答