正则表达式从电子表格公式中提取有效的单元格引用

时间:2014-01-18 02:50:23

标签: javascript regex google-apps-script google-sheets

我正在尝试使用Google Apps脚本(Javascript)从电子表格公式中提取有效的单元格引用和范围引用。

有效的单元格引用是一个或两个字母,后跟连续的数字不以零开头。字母或数字可以或可以不以$字符开头。整个引用不能在字母,数字或下划线之前/之后(在这种情况下它可能是电子表格函数或命名范围的名称的一部分)或冒号(在这种情况下它可能是范围参考)。

范围参考正则表达式(rangeRefRe)似乎运作良好;但我的单元格引用正则表达式(cellRefRe)无法找到匹配项。如果有人能够指出我做错了什么会很棒。

function myFunction()
{
  var formula = '=A100+B$2:2+INDIRECT("A2:B")+$C3-SUM($D$1:$E5)';
  var fSegments = formula.split('"'); // I want to exclude references within double quotation marks
  var rangeRefRe = /[^0-9a-zA-Z_$]([0-9a-zA-Z$]+?:[0-9a-zA-Z$]+)(?![0-9a-zA-Z_])/g;
  var cellRefRe = /[^0-9a-zA-Z_$:](\${,1}[a-zA-Z]{1,2}\${,1}[1-9][0-9]*)(?![0-9a-zA-Z_:])/g;
  var refResult;
  var references = [];
  for (var i = 0; i < fSegments.length; i += 2)
  {
    while (refResult = rangeRefRe.exec(fSegments[i]))
    {
      references.push(refResult[1]);
    }
    while (refResult = cellRefRe.exec(fSegments[i]))
    {
      references.push(refResult[1]);
    }
  }
  Logger.log(references);
}

5 个答案:

答案 0 :(得分:3)

JavaScript不支持正则表达式的这一部分:{,1}。要允许0或1次出现,则需要{0,1},或者只用?替换它:

/[^0-9a-zA-Z_$:](\$?[a-zA-Z]{1,2}\$?[1-9][0-9]*)(?![0-9a-zA-Z_:])/g;

答案 1 :(得分:3)

问题和答案非常有用,但我遇到了一些问题,所以这里有一些未来读者的注意事项:

  1. 最好在正则表达式无法结束的字符中添加“(”。公式可以包含对名为“a1”或类似名称的自定义函数的调用。添加左括号会阻止将调用与这些名称很差的自定义函数进行匹配。

  2. 虽然“A2:A”和“A1:2”是有效范围,但“A:2”之类的范围不是。

  3. 我需要按照它们在公式中出现的方式排序。范围和单元格的单个正则表达式可以解决该问题。

  4. 这是我提出的正则表达式:

    /[^0-9a-zA-Z_$:]\$?([a-zA-Z]+(\$?[1-9]\d*(:(\$?[a-zA-Z]+)?\$?([1-9]\d*)?)?|((:\$?[a-zA-Z]+\$?([1-9]\d*)?))))(?![0-9a-zA-Z_(])/g;

答案 2 :(得分:1)

正确的正则表达式应该是:

/[^0-9a-zA-Z_$:](\$?[a-zA-Z]{1,2}\$?[1-9][0-9]*)(?![0-9a-zA-Z_:])/

答案 3 :(得分:0)

Josh Dawson对正则表达式posted的变化,包括表格名称。

var formula = '=data!A100+B$2:2+INDIRECT("A2:B")+\'Sheet 1\'!$C3-SUM($D$1:$E5)';
var fSegments = formula.split('"'); // I want to exclude references within double quotation marks
var re = /[^0-9a-zA-Z_$:]((((\'.+\')|([a-zA-Z0-9]+))\!)?\$?([a-zA-Z]+(\$?[1-9]\d*)(:(\$?[a-zA-Z]+)?\$?([1-9]\d*)?)?|((:\$?[a-zA-Z]+\$?([1-9]\d*)?))))/g;
var refResult;
var references = [];
for (var i = 0; i < fSegments.length; i += 2) {
  while (refResult = re.exec(fSegments[i])) {
    references.push(refResult[1]);
  }
}
console.log(references);

答案 4 :(得分:0)

我在R中做过同样的事情,并以为我要添加我的方法。它包括对外部工作簿的引用。我没有包括B$2:2之类的东西,因为我从未在野外看到它们。

# Thanks to https://www.get-digital-help.com/2017/02/07/extract-cell-references-from-a-formula/
library(stringr)
formula <- "=data!A100+'[C:\\temp dir\\book.xlsx]Sheet 1'!$C3-SUM($D$1:$E5)"
book <- "\\[[a-zA-Z0-9][a-zA-Z0-9\\s\\+\\-\\&\\_\\.\\:\\\\]*\\]" # add any needed filepath characters
sheet <- "[a-zA-Z][a-zA-Z0-9\\s\\+\\-\\&\\_\\(\\)]*" # add any needed sheetname characters
range <- "\\$?[A-Z]+\\$?[0-9]+(:\\$?[A-Z]+\\$?[0-9]+)?(?!\\()" # not followed by (
pattern <- paste0("('?((", book, ")?", sheet, ")'?!)?", range)
pattern
#> [1] "('?((\\[[a-zA-Z0-9][a-zA-Z0-9\\s\\+\\-\\&\\_\\.\\:\\\\]*\\])?[a-zA-Z][a-zA-Z0-9\\s\\+\\-\\&\\_\\(\\)]*)'?!)?\\$?[A-Z]+\\$?[0-9]+(:\\$?[A-Z]+\\$?[0-9]+)?"
str_extract_all(formula, pattern, simplify=TRUE) # matrix
#>      [,1]        [,2]                                     [,3]      
#> [1,] "data!A100" "'[C:\\temp dir\\book.xlsx]Sheet 1'!$C3" "$D$1:$E5"

reprex package(v0.2.1)于2019-03-14创建