Javascript 用于替换的JS(无回溯)正则表达式:绑定SQL变量而不替换';冒号:in:literals'。。。?

Javascript 用于替换的JS(无回溯)正则表达式:绑定SQL变量而不替换';冒号:in:literals'。。。?,javascript,mysql,regex,Javascript,Mysql,Regex,为了搞乱节点mysql,我编写了一些代码,让我可以使用PDO风格:绑定值(plus::bound字段名),并用?那么??并在执行语句时构建一个值的线性数组。我这样做是因为当我看到一个SQL语句中有大量的??到处都是,我得数一数执行中的参数数量,这让我的眼睛流血。我只想在执行时分配一个标准对象 问题是,在写了这篇文章(它起作用)之后,我意识到我在语句中查找冒号的正则表达式有一个小问题,即它看起来像这样: /.?:(\w+)/g 如果需要,它会拾取第一个冒号,然后我们从那里取下它。问题是,它还会在

为了搞乱节点mysql,我编写了一些代码,让我可以使用PDO风格:绑定值(plus::bound字段名),并用?那么??并在执行语句时构建一个值的线性数组。我这样做是因为当我看到一个SQL语句中有大量的??到处都是,我得数一数执行中的参数数量,这让我的眼睛流血。我只想在执行时分配一个标准对象

问题是,在写了这篇文章(它起作用)之后,我意识到我在语句中查找冒号的正则表达式有一个小问题,即它看起来像这样:

/.?:(\w+)/g
如果需要,它会拾取第一个冒号,然后我们从那里取下它。问题是,它还会在查询中拾取文本中的冒号。因此,如果出于某种原因,您需要一个非绑定字符串作为insert/update的一部分,那么它将被此引擎替换

是否有任何标准的正则表达式用于在下面的语句中拾取单词“:param{#}”的每个全局实例,而不拾取单词“Hello:world”,在JS中,不进行回溯

INSERT INTO test VALUES(:param1, :param2, 'Hello:world', :param3);

编写解析器通常比使用正则表达式要好得多。它更加灵活,为您提供更好的错误报告,并允许您更轻松地处理当前和未来的边缘情况

字符串解析处理所描述的MySQL字符串文本语法和转义序列,只是跳过它们

我不是在处理有效/无效的绑定边界,但是如果需要,您可以添加它。您还可以删除错误报告,例如未终止的字符串文本,并且请原谅

lookahead===':'&&peek()
条件是忽略
:=
MySQL操作符

constparsebindings=(()=>{
常量bindingCharRx=/\w/;
返回函数(sql){
常量绑定=[];
设i=0,
lookahead=sql[i];
while(向前看){
if(isStringDelim(lookahead))parseString();
如果(lookahead===':'&&peek()!=='='=')parseBinding();
否则消耗();
}
返回绑定;
函数parseString(){
const start=i,
delim=向前看;
消费();
while(向前看){
如果(向前看=='\\'){
消费();
消费();
继续;
}
如果(向前看===delim){
消费();
if(lookahead!==delim)返回;
}
消费();
}
抛出新错误(`Underterminated string literal start at index${start}.`);
}
函数isStringDelim(char){
返回char===“'”| char===“'”;
}
函数parseBinding(){
const start=i;
消费();
while(lookahead&&bindingCharRx.test(lookahead))consume();
const name=sql.slice(start+1,i);
如果(!name.length){
抛出新错误(`从索引${start}开始的绑定无效。`);
}
绑定。推送({
开始
完:我,,
姓名:姓名
});
}
函数消耗(){
lookahead=sql[++i]
}
函数peek(){
返回sql[i+1]
}
}
})();
函数replaceNamedBindings(值,sql){
constbindings=parseBindings(sql);
const bindingNames=新集合(bindings.map(b=>b.name));
const unknownBinding=Object.keys(values.find)(k=>!bindingNames.has(k));
if(unknownBinding)抛出新错误(`找不到名为'${unknownBinding}'的绑定')`);
设lastIndex=0,
newSql='';
for(绑定的常量绑定){
if(值中的binding.name){
newSql+=sql.slice(lastIndex,binding.start)+值[binding.name];
lastIndex=binding.end;
}
}
newSql+=sql.slice(lastIndex);
返回newSql;
}
const sql=`插入测试值(:param1,:param2,'Hello:world',:param3);`;
console.log(replaceNamedBindings({
param1:“(param1值)”,
param2:“(param2值)”,
param3:'(param3值)'
},sql));
log(parseBindings(sql));
log(解析绑定(`:pickup1:dontpickup1'':dontpickup2':=''”:dontpickup3''':dontpickup4'\\\“:dontpickup5:pickup2');
//将引发异常b/c:世界不是绑定
console.log(replaceNamedBindings({
世界:‘(世界价值)’

},sql))谢谢你的全面回答!正确的错误处理和所有。好极了@乔希:没问题!我不知道你到底需要什么,但你应该能够扩展这个答案。如果你需要调整,请告诉我。就像我说的,我没有处理像
:param1#O这样的案件$(#
无效,b/c许多运算符是非
\w
,但有效。您必须将它们全部枚举以使其防弹,例如
+
*
等。因此
:param1+:param2
有效,但
:param1#:param2
无效。您也可以强制在参数之间留一个空格以简化操作。祝您好运int。我认为我从未将参数命名为非w,但在我的例子中,从SQL错误中可以明显看出问题所在。我的用法是设置服务器端,并使用mysqljs模拟准备好的语句,因此我将所有绑定的:params转换为?(和::fields转换为??,如果可能,在模拟下)然后返回一个语句对象,其中包含绑定名称的有序列表,可以稍后在async.PDO样式的mysqljs上执行。目前这很好,我在Typescript中为额外的::字段冒号使用了peek()。我将发布一个GH链接并感谢您!我已经在fi中包含了您的解析器