Javascript正则表达式:要排除所有大写形式的功能词

时间:2019-06-28 15:42:23

标签: javascript regex

我有以下正则表达式来解析google脚本公式以获取先例

if Dog is not None:
  ...

我需要使数字可选,以适应整个列的范围,请参见图像。因为数字是可选的,所以我还要匹配要排除的功能项(全部大写的单词)。我想我可以在事后这样做,但是我想修改正则表达式以排除它们。我该怎么办?

示例:

([A-z]{2,}!)?:?\$?[A-Z]\$?[A-Z]?(\$?[1-9]\$?[0-9]?)?

我要匹配的单词是指具有可选工作表名称和在行或列标识符之前为可选=IFERROR(VLOOKUP($AA16,Account_List_S!$AA:$AC,3,0),0) IFERROR(IF(AD3=1,INDEX(CapEx!$AB$15:$AE$15,1,YEAR(AD$13)- YEAR($Z$13)-1)*IF(Import_CapEx!AD$15>=0,Import_CapEx!AD$15,0),0),0)"; 的单元格。它们可以是范围或单个单元格。

我要匹配的单词示例:

$

我要排除的单词是函数:

$AA16
$AB$15
AD$15
$Z$13
Account_List_S!$AA:$AC
CapEx!$AB$15:$AE$15
Import_CapEx!AD$15

image shows results

3 个答案:

答案 0 :(得分:3)

尝试此正则表达式:

/[\(,+\-\*/><=]((\w+!)?\$?[A-Z]{1,2}(\$?[\d]{0,3})?(:\$?[A-Z]{1,2}(\$?\d{0,3})?)?(?=[\),+\-\*/><=]))/g

虽然时间长一点,但它的优点是当在公式中找到它们时将拒绝它们:

  • 具有[A-Z]和[0-9]但没有列的任何内容,例如ZIP50210
  • 具有[A-Z]和[0-9]但顺序错误的任何内容,例如25E
  • 任何变量,例如"AR"'JOHN'
  • 公式中的任何常量,例如TRUEFALSE或其他参数值

说明:

  

[\(,+\-\*/><=]寻找起始文字(,+,-,/,*,>,<,=之类的操作数。我们希望列标识符以这些字符开头。

     

(现在我们开始匹配组

     

(\w+!)?允许使用可选的工作表名称,例如'Account_List_S!'

     

\$?[A-Z]{1,2}(\$?[\d]{0,3})?将匹配诸如A$B1$AB$12AB123的列

     

(:\$?[A-Z_$]{1,2}(\$?[\d]{0,3}))?为一系列列添加可选匹配项,例如尾随:DD:$C1:AC$1:AC123或类似的

     

(?=[,\)=:><])提前结束字面量),+,-,/,*,>,<,=之类的操作数。我们希望列标识符以这些字符结尾。

     

)紧密匹配的组

     

g全局匹配(不止一个实例)

演示:

let regex =     /[\(,+\-\*/><=]((\w+!)?\$?[A-Z]{1,2}(\$?[\d]{0,3})?(:\$?[A-Z]{1,2}(\$?\d{0,3})?)?(?=[\),+\-\*/><=]))/g;

let str = '=IFERROR(VLOOKUP($AA16,Account_List_S!$AA:$AC,3,0),0)IFERROR(IF(AD3=1,INDEX(CapEx!$AB$15:$AE$15,1,YEAR(AD$13)-YEAR($Z$13)-1)*IF(Import_CapEx!AD$15>=0,Import_CapEx!AD$15,0),0),0)";';

let arr = []

while(match = regex.exec(str)) {
    arr.push(match[1]); //we only want the first matching group
}

console.log(arr);
/*
    [ '$AA16',
    'Account_List_S!$AA:$AC',
    'AD3',
    'CapEx!$AB$15:$AE$15',
    'AD$13',
    '$Z$13',
    'Import_CapEx!AD$15',
    'Import_CapEx!AD$15' ] */

答案 1 :(得分:0)

第一枪:过滤掉全部大写单词

这个答案还不是完美的,但是在表达式的开头使用否定的前瞻可以使您过滤掉IF和任意3个以上大写字母的序列:

(?!\b[A-Z]{3,}\b|\bIF\b)(\b[A-z]{2,}!)?:?\$?\b[A-Z]\$?[A-Z]?(\$?[1-9]\$?[0-9]?)?\b

\b在几个地方是要确保正负匹配从字母序列的开始到结尾。

剩下的问题是,它在Account_List_S!$AA:$ACAccount_List_S!$AA这两个匹配项中匹配:$AC。所以...

第二张照片:修复正则表达式的正匹配部分

这是一个更复杂的版本,可以正确匹配范围:

编辑:已修复,可以处理OP在注释中给出的示例。

(?!\b[A-Z]{3,}\b|\bIF\b)(\b[A-z]{2,}!)?\$?\b[A-Z]{1,3}(\$?[1-9]{1,3})?(:\$?[A-Z]{1,3}(\$?\d{1,3})?)?\b

在这个版本中,Account_List_S!$AA:$AC在整体上是匹配的,正如我相信的那样,在下面的注释中也添加了Calc_Named_HC!AE$32:AE$103

第三张照片:接受一些伪造图案,但更易于阅读

如果您愿意在第一个地址之前接受多余的:匹配,则可以使用以下更简单的表达式:

编辑:已修复,可处理注释中给出的示例。

(?!\b[A-Z]{3,}\b|\bIF\b)(\b[A-z]{2,}!)?(:?\$?\b[A-Z]{1,3}(\$?\d{1,3})?){1,2}\b

请注意,我将您的[A-z]范围保持不变,但正如{sp00m在其评论中指出的那样,[A-Za-z_]可能更合适。

答案 2 :(得分:0)

感觉不适合使用正则表达式,但是我不能忽略正则表达式的挑战。

我的解决方案涉及很多条件检查

(\w+\!)?\$?[A-Z]{1,}(?:\d+)?(\:?\$\w+)*(?!\()\b

故障

(
  \w+\!        Words followed by an !
)?             which might exist.
\$?            A $ which might exist
[A-Z]{1,}      At least 1 capitalized letter maybe more
(?:                 
   \d+         A non capturing group of digits after our letters
)?             but they might not exist

(
  \:?          A : which might exist
  \$\w+        A $ followed by characters
)*             With none or many of them

(?!\()         All of this, ONLY IF we DONT have a ( after it
\b             All of this, ONLY IF we have a word break

魔术实际上是在有条件中断的最后发生的,没有它们,您就会捕获很多其他东西。


样品

let text = `=IFERROR(VLOOKUP($AA165,Account_List_S!$AA:$AC,3,0),0)
IFERROR(IF(AD3=1,INDEX(CapEx!$AB$15:$AE$15,1,YEAR(AD$13)-
YEAR($Z$13)-1)*IF(Import_CapEx!AD$15>=0,Import_CapEx!AD$15,0),0),0)";`

let exp = /(\w+\!)?\$?[A-Z]{1,}(?:\d+)?(\:?\$\w+)*(?!\()\b/gm

let match;
while((match=exp.exec(text))) {
    console.log(match[0]);
}

输出:

$AA165
Account_List_S!$AA:$AC
AD3
CapEx!$AB$15:$AE$15
AD$13
$Z$13
Import_CapEx!AD$15
Import_CapEx!AD$15

对表达式进行简单的更改:在$:后面加上$使其适用于您添加的用例

(\w+\!)?\$?[A-Z]{1,}(?:\d+)?(\:?\$?\w+)*(?!\()\b

let text = `$X74,Calc_Named_HC!AE$32:AE$103)-Calc_General_HC!AE74";`
let exp = /(\w+\!)?\$?[A-Z]{1,}(?:\d+)?(\:?\$\w+)*(?!\()\b/gm
let match;
while((match=exp.exec(text))) {
    console.log(match[0]);
}