【问题标题】:Replacing leading spaces in formatted numbers替换格式化数字中的前导空格
【发布时间】:2012-12-28 23:21:09
【问题描述】:

我想用\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)
}

唯一缺少的部分是不是替换if() 部分中\phantom 中的所有空格,而是替换空格的数量-n,其中n &lt;- 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)会更好。

【问题讨论】:

  • 这就是为什么会有if()... 对于x 的那些带有大标记的元素,我们替换所有的空格。对于x的那些没有大标记的元素,至少有三个空格(由于有些元素有大标记,所以我们将big.mark粘贴到这些字符串中)
  • 我展示的代码是目前我所知道的最好的,但它没有做正确的事情(在 R 和 LaTeX 中都没有)。问题是对于那些没有大标记的 x 元素,\phantom{ } 引入了太多空间(即n 空间太多,其中nbig.mark 中的字符数)。
  • 我现在(更新 3)做得更优雅。但是,如果我们可以省略参数 big.mark2,那就太好了。

标签: regex r format


【解决方案1】:

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

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

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

【讨论】:

  • 应该在模式的开头放置一个^,以确保它只抓取前导空格。可能也应该做sub
  • 非常感谢!现在正如您所料,\phantom{} 命令适用于 LaTeX。为了使这种格式更有用,幻象命令确实应该考虑big.mark 保留的空间\\\\,(LaTeX 中的\,)。如果您也知道解决方案,那就太好了。换句话说,sub() 应该考虑到nchar("\\\\,") (=3)。
  • 我猜我们正在寻找的“算法”是这样的:如果big.mark 没有数字,那么到目前为止的解决方案很好。如果至少有一个带有big.mark 的数字,那么也将phantom{} 中的big.mark 添加(=粘贴)到该数字(字符串)。这可能是我们可以保证之后数字正确对齐的唯一方法,因为我们不知道 big.mark 在 LaTeX 中占用的实际空间(当前示例 big.mark=\\\\, 占用了 \, 空间LaTeX——我什至不确定这在 LaTeX 中是否是半个空白)
  • 我承认我很惊讶看到要在替换参数中评估 R 表达式,但在这种情况下不需要它,因为这会给出相同的结果:sub("^([ ]+)", "\\\\phantom{\\1}", y)
  • 亲爱的 Arun,请查看第二次更新。如何替换空格数减去n (= 3)?
猜你喜欢
  • 2017-06-02
  • 1970-01-01
  • 2012-09-14
  • 2016-12-05
  • 2014-04-27
  • 2014-02-04
  • 1970-01-01
  • 2018-10-04
  • 1970-01-01
相关资源
最近更新 更多