我正在编写一些分析一些SQL表达式的代码,但遇到了一个我自己无法解决的问题。我想替换SQL语句中的某个单词,但如果该单词包含在单引号或双引号中的话,则不替换该词。我的用例是SQL表达式解析,但我认为这更像是泛型字符串替换。
要举一个例子,请考虑表达式:select {foo} from Table where {foo} = "This is {foo} today" or {foo} = 'this is {foo} tomorrrow' or {foo} = "it's all '{foo}' to me!"
假设我想将{foo}
替换为字符串bar
,则输出为:select bar from Table where bar = "This is {foo} today" or bar = 'this is {foo} tomorrow' or bar = "it's all '{foo}' to me!"
正如我们所看到的,所有包含在引号(单引号或双引号)中的{foo}
表达式都没有被替换。
我们可以假设引号将被关闭,即不会有浮动的杂乱引号(where {foo} = 'un'even"
不是我们需要考虑的用例)。
嵌套引号中的文本不应被替换(不管您如何看待它,文本包含在引号中:)该示例在or {foo} = "it's all '{foo}' to me!"
部件中显示了此示例(以及包含三个单引号只是为了好玩)
我对此做了相当多的研究,在Javascript (或任何其他语言无疑)中,这似乎是一件棘手的事情。这似乎很适合regex,但是任何javascript解决方案regex都会有帮助。我在堆栈溢出中最接近解决方案的是如果正则表达式被字符括起来,则不要替换regex。,但这还不足以提供帮助。
发布于 2022-10-24 23:54:31
对于使用JavaScript的示例字符串,可以使用带有回调的单个模式作为捕获组来检查。
(['"]).*?\1|({foo})
模式匹配:
(['"])
组1,捕获"
或'
.*?
匹配任何字符,尽可能少\1
匹配第1组捕获的相同字符|
或({foo})
捕获第2组的{foo}
在第2组的回调检查中,如果它在那里,返回它,否则返回整个比赛。
const regex = /(['"]).*?\1|({foo})/g;
const str = `select {foo} from Table where {foo} = "This is {foo} today" or {foo} = 'this is {foo} tomorrrow' or {foo} = "it's all '{foo}' to me!"`;
const result = str.replace(regex, (m, _, g2) => g2 ? "bar" : m);
console.log(result);
发布于 2022-10-24 22:15:54
您可以使用回调在'.+?'|\{foo\}
上执行regex替换,并且只能在后面的匹配中进行替换。注意,SQL中的字符串文字使用单引号,而不是双引号。因此,我将重构您的查询,使之只对字符串使用单引号。
var sql = "select {foo} from Table where {foo} = 'This is {foo} today' or {foo} = 'this is {foo} tomorrrow' or {foo} = 'it''s all ''{foo}'' to me!'";
var output = sql.replace(/'.+?'|\{foo\}/g, (x) => x.match(/^\{.*\}$/) ? "bar" : x);
console.log(output);
备注:
{foo}
,而不是字符串文本。''
加倍而形成的。发布于 2022-10-24 22:43:14
我怀疑是否可以直接在特定示例中使用唯一的正则表达式,因为单引号、交错单引号或双引号、优先级冲突等都有可能实现。我认为,最好的方法是编写一个简单的天真解决方案,它适用于大多数用例,然后查看是否有用于优化的rooom。
类似Javascript中的以下内容正在工作,即使不是最优的(例如,用回调替换可能不太容易,但却非常简洁):
const source = `select {foo} from Table where {foo} = "This is {foo} today" or {foo} = 'this is {foo} tomorrow' or {foo} = "it's all '{foo}' to me!"`;
const solution = `select bar from Table where bar = "This is {foo} today" or bar = 'this is {foo} tomorrow' or bar = "it's all '{foo}' to me!"`;
const exclusions = [];
const exclusionPatterns = [/\".*?\"/g, /\'.*?\'/g];
let modifiedSource = source;
for (const pattern of exclusionPatterns) {
let matches;
while (true) {
matches = modifiedSource.match(pattern);
if (!matches) {
break;
}
const firstMatch = matches[0];
modifiedSource = modifiedSource.replace(
firstMatch,
`$${exclusions.length}`
);
exclusions.push(firstMatch);
}
}
const destination = modifiedSource.replace(/(\{foo\})+/g, "bar");
let modifiedDestination = destination;
for (const [index, exclusion] of exclusions.entries()) {
modifiedDestination = modifiedDestination.replace(`$${index}`, exclusion);
}
console.log(source);
console.log(modifiedSource);
console.log(modifiedDestination);
console.log(solution);
https://stackoverflow.com/questions/74189654
复制相似问题