替换格式化数字中的前导空格

时间:2012-12-28 23:21:10

标签: regex r format

我想用\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)会更好。

1 个答案:

答案 0 :(得分:3)

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

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

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