【问题标题】:Latex expression replacement in RR中的乳胶表达式替换
【发布时间】:2018-01-28 22:47:50
【问题描述】:

我正在使用 R 中的 LaTex 文档,我需要将 {#1 \over #2} 更改为 \frac{#1}{#2}

使用简单的表达式,例如:

  • {1\over 2}
  • {x^2+y^2\over \lambda}

我可以使用 stringr::str_replace()gsub 基本函数和正则表达式 \\{([\\^a-z0-9\\\\\\s\\+\\-\\*/\(\)]+)\\s*\\\\over\\s*([\\^a-z0-9\\\\\\s\\+\\-\\*/\(\)]+)\\} 来做到这一点(我想必须有更好的方法来做到这一点。我尝试使用 \\{(.+)\\s*\\\\over\\s*(.*)\\} 但它捕获的比我想要的要多.)

但是当我使用以下表达式时:

  • {e^{2c} \over x-1}
  • {2yz\over 1+x^{2} }

或更复杂的表达式:

  • \\item $Dom\\left(Q\\right)\\ne {\\rm R}^{2} $ y uno de los puntos no pertenecientes al dominio es $\\left({1\\over 2} ,{1\\over 2} \right).$

上述正则表达式失败。

是否有一个正则表达式可以捕获所有替代方案?谢谢

【问题讨论】:

  • 我会为此删除正则表达式,而是在字符串中找到\over 的位置,然后将除第一个{ 之外的所有内容用于#1 以及除最后一个} 之外的所有内容为#2。然后构建替换字符串。
  • paste("\\frac", gsub("\\\\over", "}{", x, perl=TRUE)) 似乎可以工作,但肯定会很容易坏
  • 您可能需要考虑使用 TeXCheckR 包中的 extract_LaTeX_argument()。
  • @user20650 有趣的解决方案 确实它运行良好,但如果我们只使用我上面放置的示例。但是这些示例在较长的表达式中,例如 \item $\left(K,\left({c\over \lambda K^{\alpha } } \right)^{{1\over \beta } } \right).$ 并且在那里它失败了。
  • @Hugh 我不知道那个包的存在。我会看看。谢谢

标签: r regex


【解决方案1】:

给定一些示例字符串:

> strings
[1] "{1\\over 2}"              "{x^2+y^2\\over \\lambda}"

这个怪物:

 > unlist(
      lapply(
         strsplit(
           sub("\\}$","",
              sub("^\\{","",strings)),"\\\\over"),
          function(x){paste0("\\frac{",x[1],"}{",x[2],"}")}))

产生:

 [1] "\\frac{1}{ 2}"              "\\frac{x^2+y^2}{ \\lambda}"

如果源字符串中有多个\over,这将中断。可能在许多其他情况下也是如此......哦,如果在第一个 { 之前或结束 } 之后有空格,它就不起作用。

在您的其他示例中,您会得到以下信息:

     in                         out                          
[1,] "{1\\over 2}"              "\\frac{1}{ 2}"             
[2,] "{x^2+y^2\\over \\lambda}" "\\frac{x^2+y^2}{ \\lambda}"
[3,] "{e^{2c} \\over x-1}"      "\\frac{e^{2c} }{ x-1}"     
[4,] "{2yz\\over 1+x^{2} }"     "\\frac{2yz}{ 1+x^{2} }"    

【讨论】:

  • 有趣的解决方案。确实它运作良好,但如果我们只使用我上面放置的示例。但这些例子在较长的表达式中,例如 \item $\left(K,\left({c\over \lambda K^{\alpha } } \right)^{{1\over \beta } } \right ).$ 并且它失败了。我没有正确提出问题是我的错。
【解决方案2】:

我很喜欢这个问题。

在某些时候,您必须解析文档。来自TeXCheckRparse_tex 考虑了LaTeX 而不是普通的TeX,但在这里似乎还可以。对于\over 的多行实例,需要更改脚本,尽管我认为原理相同。

挑战在于连分数。


library(data.table) # for shift
library(TeXCheckR)  # for parse_tex

locate_over <- function(doc_parsed) {
  lead <- function(x, n) data.table::shift(x, n = n, type = "lead", fill = "")
  char <- .subset2(doc_parsed, "char")
  which(char == "\\" &
          lead(char == "o", 1L) &
          lead(char == "v", 2L) &
          lead(char == "e", 3L) &
          lead(char == "r", 4L))
}


over2frac <- function(lines, verbose = FALSE) {
  out <- lines
  for (i in seq_along(lines)) {
    if (grepl("\\over", lines[i], fixed = TRUE)) {
      i_parsed <- parse_tex(lines[i])

      # Find lhs
      for (j in locate_over(i_parsed)) {
        lhs_start <- max(which(.subset2(i_parsed, "char") %chin% c("$", "{") &
                                 .subset2(i_parsed, "column") < j &
                                 .subset2(i_parsed, "tex_group") == .subset2(i_parsed[j], "tex_group")))

        rhs_end <- min(which(.subset2(i_parsed, "char") %chin% c("$", "}") &
                               .subset2(i_parsed, "column") > j + 4L &
                               .subset2(i_parsed, "tex_group") == .subset2(i_parsed[j], "tex_group")))

        i_parsed[lhs_start, char := "{\\frac{"]
        i_parsed[rhs_end, char := "}}"]
      }
      res <- paste0(i_parsed[["char"]], collapse = "")
      res <- gsub("\\over", "}{", res, fixed = TRUE)
      out[i] <- res
    }
  }
  out
}

测试 TeX 文档:

$5 \over 2$

This is another fraction: ${1 \over 2}$.

And another:
$$A = a \over b$$

What about:
$${{D \over C} \over H}$$

Finally:

$${e^{2c} \over x-1}$$


${2yz\over 1+x^{2} }$

$$\phi = 1 + {1 \over {1 + {1 \over {1 + {1 \over {1 + \ddots}}}}}}$$

\item $Dom\left(Q\right)\ne {\rm R}^{2} $ y uno de los puntos no pertenecientes al dominio es $\left({1\over 2} ,{1\over 2}\right).$

\bye

生成的 LaTeX 文档:包含必要的 LaTeX 特定内容,以及内联分数的强制数学模式。 writeLines(over2frac(readLines("tex1.tex"), verbose = FALSE), "latex1.tex")

\documentclass{article}
\begin{document}

${\frac{5 }{ 2}}$

This is another fraction: ${\frac{1 }{ 2}}$.

And another:
${\frac{A = a }{ b}}$

What about:
$${\frac{{\frac{D }{ C}} }{ H}}$$

Finally:

$${\frac{e^{2c} }{ x-1}}$$


${\frac{2yz}{ 1+x^{2} }}$

$$\phi = 1 + {\frac{1 }{ {1 + {\frac{1 }{ {1 + {\frac{1 }{ {1 + \ddots}}}}}}}}}$$

\item $Dom\left(Q\right)\ne {\rm R}^{2} $ y uno de los puntos no pertenecientes al dominio es $\left({\frac{1}{ 2}} ,{\frac{1}{ 2}} \right).$


\end{document}

【讨论】:

  • 像我预期的那样复杂一点,但它可以工作。谢谢
  • 在我忘记之前,您应该修改 locate over 以检查“r”之后的字符是否不是字母(以避免在 \overline 等处中断)
【解决方案3】:

这为您的示例提供了大部分途径:

library(stringr)

s <- "Expression 1 is {1\\over 2}.

Expression 2 is {x^2+y^2\\over \\lambda}, yes it is.

Expression 3 is {e^{2c} \\over x-1}.

The last expression: {2yz\\over 1+x^{2} }, all done now."

s2 <- str_replace_all(s, 
                      "\\{(.*?)\\s{0,}\\\\over\\s{0,}(.*?)\\}", 
                      "\\frac\\{\\1\\}\\{\\2\\}")

s2
[1] "Expression 1 is frac{1}{2}.\n\nExpression 2 is frac{x^2+y^2}{\\lambda}, yes it is.\n\nExpression 3 is frac{e^{2c}}{x-1}.\n\nThe last expression: frac{2yz}{1+x^{2} }, all done now."

唯一的问题是最后一个表达式中保留了一个空格,这可能不是问题,因为它存在于原始表达式中:

frac{2yz}{1+x^{2} }

【讨论】:

  • 感谢您的回复。问题是它不适用于表达式\\item $Dom\\left(Q\\right)\\ne {\\rm R}^{2} $ y uno de los puntos no pertenecientes al dominio es $\\left({1\\over 2} ,{1\\over 2} \right).$ 我的问题没有更具体是我的错。对不起。
【解决方案4】:
x=c("{e^{2c} \\over x-1}","{2yz\\over 1+x^{2} },,dty{k^4e{-rpi/3}\\over\\sqrt{2pik}}")

gsub("\\{(.*?)\\\\over(.*?)\\}","\\\frac{\\1}{\\2}",x)

[1] "\frac{e^{2c} }{ x-1}"                                       
[2] "\frac{2yz}{ 1+x^{2} },,dty\frac{k^4e{-rpi/3}}{\\sqrt{2pik}}"

解释:

\{(.*?)\\over(.*?)\\

  • 列表项{ 匹配字符 { 字面意思(区分大小写)

第一捕获组 (.*?)

  • .*?匹配任何字符(行终止符除外)
  • *?量词——在零次和无限次之间匹配,尽可能少,根据需要扩展(惰性)

\\ 匹配 字符 \ 从字面上(区分大小写)过度匹配字符 在字面上(区分大小写)

第二捕获组 (.*?)

  • .*?匹配任何字符(行终止符除外)
  • *?量词 - 在零次和无限次之间匹配,尽可能少,根据需要扩展(惰性)

\\ 匹配字符 \ 字面意思(区分大小写)

【讨论】:

  • 感谢您的回复。问题是它不适用于表达式\\item $Dom\\left(Q\\right)\\ne {\\rm R}^{2} $ y uno de los puntos no pertenecientes al dominio es $\\left({1\\over 2} ,{1\\over 2} \right).$ 我的问题没有更具体是我的错。对不起。
  • 它有什么作用?
【解决方案5】:

这种方法可以处理:

  • 在同一行包含 \over 的多个 {...}
  • {...} 不包含 \over
  • 在 {...} 出现之前、之后和之间的其他文本
  • 没有任何 {...} 的行带有 \over

例如,在下面的示例中,请注意,在第一次出现带有 \over 的 {...} 之前,第二个输入行上的 {jjj} 按预期工作。

它利用了gsubfn 可以处理平衡括号。首先创建一个原型对象p,类似于我的答案herep 将计数器 k 初始化为 0,并为每个 { 增加它并为每个 } 减少它。它将 k=1 的任何 { 替换为 !以及任何 k=0 的 } 和 !。

然后将!...\over...! 替换为\frac{...}{...},并将剩余的!...! 替换为{...}

我们假设!不会出现在输入中,但如果它确实选择了不同的字符。

library(gsubfn)
library(magrittr)

# test input
s <- c("abc {1\\over 2} def {x^2+y^2\\over \\lambda} ghi { 12 } XYZ",
       "X {jjj} A {e^{2c} \\over x-1} jkl {2yz\\over 1+x^{2} } Z")

# processing

p <- proto(
 pre = function(.) .$k <- 0,
 fun = function(., x) {
  if (x == "{") .$k <- .$k + 1 else if (x == "}") .$k <- .$k - 1
  if (x == "{" && .$k == 1) "!" else if (x == "}" && .$k == 0) "!" else x
})

s %>%
  gsubfn("[{}]", p, .) %>%
  gsub("!([^!]*)\\\\over ([^!]*)!", "\\\\frac{\\1}{\\2}", .) %>%
  gsub("!([^!]*)!", "{\\1}", .)

给出这个结果:

[1] "abc \\frac{1}{2} def \\frac{x^2+y^2}{\\lambda} ghi { 12 } XYZ"
[2] "X {jjj} A \\frac{e^{2c} }{x-1} jkl \\frac{2yz}{1+x^{2} } Z"   

【讨论】:

    猜你喜欢
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    相关资源
    最近更新 更多