Регулярное выражение Javascript: хочу исключить функциональные слова во всех заглавных буквах - PullRequest
2 голосов
/ 28 июня 2019

У меня есть следующее регулярное выражение для синтаксического анализа формулы сценария Google для получения прецедентов

([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

Слова, которые я хочу исключить, являются функциями:

IFERROR
VLOOKUP
IF
YEAR    

image shows results

Ответы [ 3 ]

3 голосов
/ 29 июня 2019

Попробуйте это регулярное выражение:

/[\(,+\-\*/><=]((\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'
  • Любые константы в формуле, такие как TRUE, FALSE или другие значения аргумента

Пояснение:

[\(,+\-\*/><=] ищите начальный литерал ( или , или такие операнды, как +,-,/,*,>,<,=. Мы ожидаем, что идентификаторы столбцов начинаются с этих символов.

( теперь мы начинаем нашу подходящую группу

(\w+!)? допускается указание необязательных имен листов, таких как 'Account_List_S!'

\$?[A-Z]{1,2}(\$?[\d]{0,3})? будет соответствовать столбцам типа A или $B1 или $AB$12 или AB123

(:\$?[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' ] */
0 голосов
/ 29 июня 2019

Это похоже на плохое соответствие регулярному выражению, но я не могу пропустить хороший вызов регулярного выражения.

Мое решение включает множество условных проверок

(\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]);
}

Ouput:

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

Простое изменение выражения с использованием $ после: option делает его работоспособным для добавленного варианта использования

(\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]);
}
0 голосов
/ 29 июня 2019

Первый выстрел: отфильтровать полные прописные слова

Этот ответ еще не идеален, но использование отрицательного упреждения в начале выражения может позволить вам отфильтровать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:$AC в двух совпадениях, Account_List_S!$AA и :$AC.Итак ...

Второй выстрел: исправить положительное совпадение части регулярного выражения

Вот более сложная версия, которая правильно соответствует диапазонам:

EDIT: исправлено для обработки примеров, приведенных 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в комментариях ниже.

Третий снимок: принимает некоторые ложные шаблоны, но легче для чтения

Если вы готовы принять совпадение с лишним : перед первым адресом, это более простое выражение будет работать:

EDIT: исправлено для обработки примеров, приведенных в комментариях.

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

Обратите внимание, что я сохранил ваш диапазон [A-z] как есть, но [A-Za-z_]может быть более уместным, как указал @ sp00m в своем комментарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...