Regex to match string not inside parentheses












0















I been struggling to find a Regex that help me match 3 different strings only if they aren't inside parentheses, but so far I have only managed to match it if it's right next to the parentheses, and in this specific situation it doesn't suit me.



To clarify I need to match the Strings "HAVING", "ORDER BY" and "GROUP BY" that aren't contained in any parentheses, no matter if the parentheses contains more than just the string.



In that case:



Select *
from some_table
group by something;


Should match, but:



Select *
from(
Select *
from some_other_table
group by something_else
)


or



Select this, and_this
from(
Select *
from some_other_table
having some_condition
)


shouldn't.



I'm not an expert in Javascript Regex, so any help you could give me would be greatly appreciated.










share|improve this question















migrated from superuser.com Jan 6 at 15:13


This question came from our site for computer enthusiasts and power users.



















  • Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

    – melpomene
    Jan 6 at 15:18











  • You need to add more information about what the string can or can't be to have a proper answer

    – Dimitri Kopriwa
    Jan 6 at 15:24
















0















I been struggling to find a Regex that help me match 3 different strings only if they aren't inside parentheses, but so far I have only managed to match it if it's right next to the parentheses, and in this specific situation it doesn't suit me.



To clarify I need to match the Strings "HAVING", "ORDER BY" and "GROUP BY" that aren't contained in any parentheses, no matter if the parentheses contains more than just the string.



In that case:



Select *
from some_table
group by something;


Should match, but:



Select *
from(
Select *
from some_other_table
group by something_else
)


or



Select this, and_this
from(
Select *
from some_other_table
having some_condition
)


shouldn't.



I'm not an expert in Javascript Regex, so any help you could give me would be greatly appreciated.










share|improve this question















migrated from superuser.com Jan 6 at 15:13


This question came from our site for computer enthusiasts and power users.



















  • Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

    – melpomene
    Jan 6 at 15:18











  • You need to add more information about what the string can or can't be to have a proper answer

    – Dimitri Kopriwa
    Jan 6 at 15:24














0












0








0








I been struggling to find a Regex that help me match 3 different strings only if they aren't inside parentheses, but so far I have only managed to match it if it's right next to the parentheses, and in this specific situation it doesn't suit me.



To clarify I need to match the Strings "HAVING", "ORDER BY" and "GROUP BY" that aren't contained in any parentheses, no matter if the parentheses contains more than just the string.



In that case:



Select *
from some_table
group by something;


Should match, but:



Select *
from(
Select *
from some_other_table
group by something_else
)


or



Select this, and_this
from(
Select *
from some_other_table
having some_condition
)


shouldn't.



I'm not an expert in Javascript Regex, so any help you could give me would be greatly appreciated.










share|improve this question
















I been struggling to find a Regex that help me match 3 different strings only if they aren't inside parentheses, but so far I have only managed to match it if it's right next to the parentheses, and in this specific situation it doesn't suit me.



To clarify I need to match the Strings "HAVING", "ORDER BY" and "GROUP BY" that aren't contained in any parentheses, no matter if the parentheses contains more than just the string.



In that case:



Select *
from some_table
group by something;


Should match, but:



Select *
from(
Select *
from some_other_table
group by something_else
)


or



Select this, and_this
from(
Select *
from some_other_table
having some_condition
)


shouldn't.



I'm not an expert in Javascript Regex, so any help you could give me would be greatly appreciated.







javascript regex string






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 6 at 16:00









melpomene

60.6k54793




60.6k54793










asked Jan 4 at 0:51









Steven GuerreroSteven Guerrero

528




528




migrated from superuser.com Jan 6 at 15:13


This question came from our site for computer enthusiasts and power users.









migrated from superuser.com Jan 6 at 15:13


This question came from our site for computer enthusiasts and power users.















  • Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

    – melpomene
    Jan 6 at 15:18











  • You need to add more information about what the string can or can't be to have a proper answer

    – Dimitri Kopriwa
    Jan 6 at 15:24



















  • Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

    – melpomene
    Jan 6 at 15:18











  • You need to add more information about what the string can or can't be to have a proper answer

    – Dimitri Kopriwa
    Jan 6 at 15:24

















Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

– melpomene
Jan 6 at 15:18





Can your code also contain strings or comments (and parentheses within those)? Such as: select * from stuff where x = '(' or select 42 -- just a comment (.

– melpomene
Jan 6 at 15:18













You need to add more information about what the string can or can't be to have a proper answer

– Dimitri Kopriwa
Jan 6 at 15:24





You need to add more information about what the string can or can't be to have a proper answer

– Dimitri Kopriwa
Jan 6 at 15:24












1 Answer
1






active

oldest

votes


















1














I assume you want to check whether a given SQL query contains HAVING, ORDER BY or GROUP BY at the top level (not within a subquery).



This is complicated by the fact that both parens and words can be contained inside of string literals ('...'), quoted identifiers ("..."), and comments (-- ...).



In the following code I assume that that's all that can "go wrong" (i.e. there are no other quoting constructs) and that no quoted characters are special (in particular, isn't treated any differently).



Idea:




  • Remove all quoted constructs like string literals and comments.

  • Remove all parenthesized groups.

  • Check the remaining string for your keywords.


And by "remove" I mean "replace by a space" because otherwise there is the possibility of new tokens being created where there were none before (e.g. hav(...)IN"asdf"g would turn into havINg if parenthesized/quoted parts were just replaced by nothing).



Implementation:






function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}








share|improve this answer


























  • Quite close, but still matches the strings inside parentheses.

    – Steven Guerrero
    Jan 6 at 18:21











  • @StevenGuerrero No, it doesn't. Did you try it?

    – melpomene
    Jan 6 at 19:38











  • @melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

    – Steven Guerrero
    Jan 8 at 1:37











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54062882%2fregex-to-match-string-not-inside-parentheses%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I assume you want to check whether a given SQL query contains HAVING, ORDER BY or GROUP BY at the top level (not within a subquery).



This is complicated by the fact that both parens and words can be contained inside of string literals ('...'), quoted identifiers ("..."), and comments (-- ...).



In the following code I assume that that's all that can "go wrong" (i.e. there are no other quoting constructs) and that no quoted characters are special (in particular, isn't treated any differently).



Idea:




  • Remove all quoted constructs like string literals and comments.

  • Remove all parenthesized groups.

  • Check the remaining string for your keywords.


And by "remove" I mean "replace by a space" because otherwise there is the possibility of new tokens being created where there were none before (e.g. hav(...)IN"asdf"g would turn into havINg if parenthesized/quoted parts were just replaced by nothing).



Implementation:






function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}








share|improve this answer


























  • Quite close, but still matches the strings inside parentheses.

    – Steven Guerrero
    Jan 6 at 18:21











  • @StevenGuerrero No, it doesn't. Did you try it?

    – melpomene
    Jan 6 at 19:38











  • @melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

    – Steven Guerrero
    Jan 8 at 1:37
















1














I assume you want to check whether a given SQL query contains HAVING, ORDER BY or GROUP BY at the top level (not within a subquery).



This is complicated by the fact that both parens and words can be contained inside of string literals ('...'), quoted identifiers ("..."), and comments (-- ...).



In the following code I assume that that's all that can "go wrong" (i.e. there are no other quoting constructs) and that no quoted characters are special (in particular, isn't treated any differently).



Idea:




  • Remove all quoted constructs like string literals and comments.

  • Remove all parenthesized groups.

  • Check the remaining string for your keywords.


And by "remove" I mean "replace by a space" because otherwise there is the possibility of new tokens being created where there were none before (e.g. hav(...)IN"asdf"g would turn into havINg if parenthesized/quoted parts were just replaced by nothing).



Implementation:






function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}








share|improve this answer


























  • Quite close, but still matches the strings inside parentheses.

    – Steven Guerrero
    Jan 6 at 18:21











  • @StevenGuerrero No, it doesn't. Did you try it?

    – melpomene
    Jan 6 at 19:38











  • @melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

    – Steven Guerrero
    Jan 8 at 1:37














1












1








1







I assume you want to check whether a given SQL query contains HAVING, ORDER BY or GROUP BY at the top level (not within a subquery).



This is complicated by the fact that both parens and words can be contained inside of string literals ('...'), quoted identifiers ("..."), and comments (-- ...).



In the following code I assume that that's all that can "go wrong" (i.e. there are no other quoting constructs) and that no quoted characters are special (in particular, isn't treated any differently).



Idea:




  • Remove all quoted constructs like string literals and comments.

  • Remove all parenthesized groups.

  • Check the remaining string for your keywords.


And by "remove" I mean "replace by a space" because otherwise there is the possibility of new tokens being created where there were none before (e.g. hav(...)IN"asdf"g would turn into havINg if parenthesized/quoted parts were just replaced by nothing).



Implementation:






function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}








share|improve this answer















I assume you want to check whether a given SQL query contains HAVING, ORDER BY or GROUP BY at the top level (not within a subquery).



This is complicated by the fact that both parens and words can be contained inside of string literals ('...'), quoted identifiers ("..."), and comments (-- ...).



In the following code I assume that that's all that can "go wrong" (i.e. there are no other quoting constructs) and that no quoted characters are special (in particular, isn't treated any differently).



Idea:




  • Remove all quoted constructs like string literals and comments.

  • Remove all parenthesized groups.

  • Check the remaining string for your keywords.


And by "remove" I mean "replace by a space" because otherwise there is the possibility of new tokens being created where there were none before (e.g. hav(...)IN"asdf"g would turn into havINg if parenthesized/quoted parts were just replaced by nothing).



Implementation:






function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}








function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}





function contains_groupy_bits(sql) {
sql = sql.replace(/'[^']*'|"[^"]*"|--[^n]*/g, ' ');
let tmp;
while ((tmp = sql.replace(/([^()]*)/g, ' ')) !== sql) {
sql = tmp;
}
return /b(?:having|orders+by|groups+by)b/i.test(sql);
}

const examples = [
`Select *
from some_table
group by something;`,

`Select *
from(
Select *
from some_other_table
group by something_else
)`,

`Select this, and_this
from(
Select *
from some_other_table
having some_condition
)`,

`select name, count(*) from things
where mark = '('
group by name -- )`,
];

for (const ex of examples) {
console.log("'" + ex + "': " + contains_groupy_bits(ex));
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 6 at 16:03

























answered Jan 6 at 15:57









melpomenemelpomene

60.6k54793




60.6k54793













  • Quite close, but still matches the strings inside parentheses.

    – Steven Guerrero
    Jan 6 at 18:21











  • @StevenGuerrero No, it doesn't. Did you try it?

    – melpomene
    Jan 6 at 19:38











  • @melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

    – Steven Guerrero
    Jan 8 at 1:37



















  • Quite close, but still matches the strings inside parentheses.

    – Steven Guerrero
    Jan 6 at 18:21











  • @StevenGuerrero No, it doesn't. Did you try it?

    – melpomene
    Jan 6 at 19:38











  • @melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

    – Steven Guerrero
    Jan 8 at 1:37

















Quite close, but still matches the strings inside parentheses.

– Steven Guerrero
Jan 6 at 18:21





Quite close, but still matches the strings inside parentheses.

– Steven Guerrero
Jan 6 at 18:21













@StevenGuerrero No, it doesn't. Did you try it?

– melpomene
Jan 6 at 19:38





@StevenGuerrero No, it doesn't. Did you try it?

– melpomene
Jan 6 at 19:38













@melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

– Steven Guerrero
Jan 8 at 1:37





@melpomeme You're right it does XD I was quite in a rush, I didn't used the function but only copied the regex :v However, just tried it works, Thank you

– Steven Guerrero
Jan 8 at 1:37




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54062882%2fregex-to-match-string-not-inside-parentheses%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Сан-Квентин

8-я гвардейская общевойсковая армия

Алькесар