I have a string

let str='(`id`=3) and (`filter`=\'test\' or (`filter`=\'1\' and `name`=\'2\'))' 

I need a string to become such an array

 let arr=[['id','=', '3'], 'and', [['filter','=', 'test'], 'or', [['filter','=', '1'], 'and', ['name', '=', 'i']]]] 

I did it

  let str = "((`id`=3) and (`filter`='te\\\'st' or (`filter`='1' and `name`='2')))"; let expression = []; let i = 0; let level = 0; let result = matches(str, /'(\\.|[^'])*'/ig, i, 't'); let text = result.text; let phrase = parseSQL(result.result, level, expression); console.log({phrase, text, expression}); console.log(getArray(expression)); function parseSQL(str, level, expression) { let j = 0; let result = matches(str, /\([^()]+\)/gi, j, `e${level}_`); let phrase = result.result; expression.push(result.text); if (result.result.match(/\(/)) { phrase = parseSQL(result.result, level + 1, expression); } return phrase; } function matches(str, regex, i, letter) { let result = str.replace(regex, function () { return `$${letter}${i++}`; }); let text = str.match(regex); return {result, text}; } 

I have an array in which there are keys with a level by which I can collect the required nested array, but I cannot figure out how to do it

  • First you need to make a type identifier for each token. To distinguish values ​​from column names and operators. All possible operators will have to describe somewhere and indicate which arguments and in what quantity they accept. To parse id between 1 and 45 or id IN(1, 6, 10) and even id=case when X=7 or X=8 then 45 else 55 end . Then decide what to do with the subqueries id IN(select x from tab ....) . In general, this is called "parsing" and the answer "how to do it" will take more than one page. It is better to use literature, for example, "The Book of the Dragon" - Mike
  • By the way, the lexical analyzer (which you have done) will need to be refined. For example, identifiers can have spaces if it is in the reverse apostrophes. And double quotes are generally valid in SQL (albeit in different dialects in different ways) - Mike

1 answer 1

Now it works as it should, all of a sudden

  let str = "((`id`='3') and (`filter`='te\\\'st' or (`filter`='1' and `name`='2')))"; let expression = []; let i = 0; let level = 0; let result = getMatches(str, /'(\\.|[^'])*'/ig, i, 't'); let text = result.text; let phrase = encryptExpression(result.result, level, expression); console.log({phrase, text, expression}); let position = phrase.match(/\$e(\d)_(\d)/); let newArr = expression[position[1]][position[2]]; newArr = getArray(expression, text, position, newArr); newArr = compareValues(newArr); console.log(newArr); function encryptExpression(str, level, expression) { let j = 0; let result = getMatches(str, /\([^()]+\)/gi, j, `e${level}_`); let phrase = result.result; expression.push(result.text); if (result.result.match(/\(/)) { phrase = encryptExpression(result.result, level + 1, expression); } return phrase; } function getMatches(str, regex, i, letter) { let result = str.replace(regex, function () { return `$${letter}${i++}`; }); let text = str.match(regex); return {result, text}; } function getArray(expression, text, position, newArr) { if (newArr.match(/([^(]+)\s+(and|or|not)\s+([^)]+)/i)) { newArr = newArr.match(/([^(]+)\s+(and|or|not)\s+([^)]+)/i).slice(1); for (let i = 0; i < newArr.length; i++) { if (newArr[i].match(/\$e(\d)_(\d)/)) { position = newArr[i].match(/\$e(\d)_(\d)/); if (expression[position[1]][position[2]].charAt(0) === '(' && expression[position[1]][position[2]].charAt(expression[position[1]][position[2]].length - 1) === ')') { newArr[i] = expression[position[1]][position[2]].substring(1, expression[position[1]][position[2]].length - 1) } } newArr[i] = getArray(expression, text, position, newArr[i]); if (typeof(newArr[i]) !== 'object') { if (newArr[i].match(/`(.*)`\s*(=|>|<|>=|<=|like|!=)\s*(\$t\d+)/i)) { newArr[i] = newArr[i].match(/`(.*)`\s*(=|>|<|>=|<=|like|!=)\s*(\$t\d+)/i).slice(1); } } } } return newArr; } function compareValues(newArr) { if (newArr instanceof Array) { for (let i = 0; i < newArr.length; i++) { if (!(newArr[i] instanceof Array)) { if (newArr[i].match(/\$t(\d+)/)) { newArr[i] = text[newArr[i].match(/\$t(\d+)/)[1]]; } } newArr[i] = compareValues(newArr[i]); } } return newArr; }