1

I am making an application where I have a string from which I will form an array with the help of regex.

Eg..,

String: DEVICE_SIZE IN ('036','048', '060','070')

Output:

{
    "DEVICE_SIZE": [
      "036",
      "048",
      "060",
      "070"
    ]
}

Like this for all string, we follow the following code to get the array data.

Here if there is a NOT keyword before the key, then we add NOT *key* like "NOT DEVICE_DISCHARGE_AIR"

Requirement:

I have a string like NOT (DEVICE_SERIES IN ('LV') AND DEVICE_VOLTAGE IN ('A','8') AND DEVICE_SIZE IN ('007','009','012','018')).

So here after NOT there is a parenthesis, so after NOT if there is a parenthesis then I need to add the key as

"NOT DEVICE_SERIES":["LV"],

"NOT DEVICE_VOLTAGE":["A", "8"] ,

"NOT DEVICE_SIZE": ['007','009','012','018']

Current scenario:

But right now, it is not adding the NOT keyword before of key.

Working Example:

const stringOne = "DEVICE_SIZE IN ('036','048', '060','070') AND DEVICE_VOLTAGE IN ('1','3') AND NOT DEVICE_DISCHARGE_AIR IN ('S') AND NOT DEVICE_REFRIGERANT_CIRCUIT IN ('H', 'C')";

const stringTwo = "DEVICE_SERIES IN ('LV') AND DEVICE_ELECTRICAL IN ('K') AND NOT (DEVICE_SERIES IN ('LV') AND DEVICE_VOLTAGE IN ('A','8') AND DEVICE_SIZE IN ('007','009','012','018'))";


const regex = /((?:\bNOT\s+)?\w+)\s+IN\s+\('([^()]*)'\)/g;

const getTransformedData = (string) => {
   return Array.from(
  string.matchAll(regex), m =>
  ({
    [m[1]]: m[2].split(/',\s*'/)
  })
 )
}


console.log(getTransformedData(stringOne)); // Working fine

console.log(getTransformedData(stringTwo)); // Need to include NOT infront of each key as it is union

How can I add NOT keyword in front of each key if it comes with the pattern of NOT and then the parenthesis like in stringTwo?

Expected result:

"NOT DEVICE_SERIES":["LV"],

"NOT DEVICE_VOLTAGE":["A", "8"] ,

"NOT DEVICE_SIZE": ['007','009','012','018']

5
  • If you are not bound to use regex, and the string has many legal formats, I would recommend using a sequential parsing approach going left to right, recognizing the tokens and delimiters such as "NOT" or "IN" or "(" and ")", parsing it into a nested syntax tree, and then using a recursive function to output the list of filters. Commented Dec 6, 2022 at 8:08
  • And you might also want to think about whether to stick with the approach "not X and not Y and not Z" to be written as "not (X and Y and Z)" opposed to the boolean logic where the equivalent statement using parentheses would be "not (X or Y or Z)". Commented Dec 6, 2022 at 8:13
  • @anubhava, I need that as well. Sorry I have covered only the NOT and after paranthesis. Commented Dec 6, 2022 at 9:55
  • @anubhava, I have missed that because it already working fine. But I need that part along with this new proposal of considering the data after NOT followed by parenthesis. Commented Dec 6, 2022 at 10:02
  • ok got it, let me get back to my laptop in few minutes and attempt a solution then Commented Dec 6, 2022 at 10:23

1 Answer 1

1

You may use this Javascript solution for your problem:

const stringOne = "DEVICE_SIZE IN ('036','048', '060','070') AND DEVICE_VOLTAGE IN ('1','3') AND NOT DEVICE_DISCHARGE_AIR IN ('S') AND NOT DEVICE_REFRIGERANT_CIRCUIT IN ('H', 'C')";
const stringTwo = "DEVICE_SERIES IN ('ALV', 'FOO') AND DEVICE_ELECTRICAL IN ('K') AND NOT (DEVICE_SERIES IN ('LV') AND DEVICE_VOLTAGE IN ('A','8') AND DEVICE_SIZE IN ('007','009','012','018'))";

const pat1 = String.raw`(\bNOT)\s+\(((?:[\w\s]+\([^)]+\))+)\)`;
const pat2 = String.raw`(\w+)\s+IN\s+\('([^()]*)'\)`;
const re1 = new RegExp(pat1 + '|' + pat2, "g");
const re2 = new RegExp(pat2, "g");
const re3 = /',\s*'/;

const getTransformedData = (string) => {
  var res = [];
  const matches = string.matchAll(re1);
  for (const match of matches) {
    if (match[1] == "NOT") {    
      res.push(...Array.from(
      match[2].matchAll(re2), m =>
      ({
        [match[1] + ' ' + m[1]]: m[2].split(re3)
      })));
    } else {
      res.push(
      ({
        [match[3]]: match[4].split(re3)
      }));
    }
  }
  return res;
}

console.log(getTransformedData(stringOne));
console.log(getTransformedData(stringTwo));

  • Regex string pat2 is same as what you already have
  • Regex string pat1 matches a string that has NOT (...) substring.
  • We combine pat1 and pat2 to build a regex re1 which is applied first against input string. This regex matches NOT (...) pattern or word in (...) sub-patterns.
  • We capture NOT in capture group #1 and text inside (...) in capture group #2.
  • When match[1] == "NOT" we apply re2 again on the match[2] to get our desired matches
  • Regex re3 is your split regex
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your great solution bro. It helps me a lot. Thanks for your effort and time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.