javascript

时间:2015-12-23 19:43:34

标签: javascript regex source-maps

我正在使用正则表达式创建一个简单的模式匹配器,它可以采用我的正则表达式模式,并以我想要的格式生成一个新的字符串。当我注意到我有相邻的正则表达式模式与彼此冲突时,看起来像一个简单的程序变得非常复杂,并且无法再正确执行操作,因为新形成的字符串包含与我刚刚替换的字符冲突的字符...(我知道它可能有点混乱,所以我提供一个例子)。

var str = "I am the greatest";
var r1 = /(am)/g;
var r2 = /(i)/ig;
var newstr = str.replace(r1,"<i>$1</i>").replace(r2,"<h1>$1</h2>");
console.log(newstr);
    //returns "<h1>I</h2> <<h1>i</h2>>am</<h1>i</h2>> the greatest"

我知道这是一个天真的例子,然而,它完美地说明了我的观点。我想要发生的是第二次(和所有进行中)替换在原始字符串上执行匹配,但是在变异字符串上进行替换,以便上面示例中的newstr var会读"<h1>I</h2> <i>am</i> the greatest"。我曾想过使用源图,引用正则表达式的地图并执行自定义替换函数,该函数引用地图以在正确的位置执行替换....但我似乎无法掌握源图实现这一点....任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

正如我在第一次更换时所看到的那样,将你更换为 am ,所以在第二次更换所有i时,这意味着你不仅要更换“我”和“它”“我”。也是,所以你得到你写的结果。 这是正则表达式,无法替换标签“i”:

r2 = /(i)[^>]/ig

答案 1 :(得分:0)

你可以想出一些你期望在字符串中找不到的字符序列,使用该序列暂时包装你所有replace的结果,然后再去掉那个序列replace已完成。

例如,选择序列为#{...},您可以将其添加到所有正则表达式模式中。类似的东西:

var seq = /#\{(.*?)\}/g; // our sequence -- #{...}

// Prepend (#\{(.*?)\})| to the given regex
var newExpression = function(regex) {
    var splitRegex = regex.toString().split('/'),
        flags = splitRegex.pop();
    splitRegex.shift(); // get rid of the first blank entry from the opening '/' in the regex
    return new RegExp('(' + seq.toString().slice(1, -2) + ')|' + splitRegex.join('/'), flags);
};

var r1 = newExpression(/(am)/g); // returns /(#\{(.*?)\})|(am)/g
var r2 = newExpression(/(i)/ig); // returns /(#\{(.*?)\})|(i)/ig
如果您不想手动将(#\{.*?\})|添加到所有模式的开头,

会这样做。我们这样做是为了让我们能够在后续传递中识别这个序列,而不是触及它。

接下来,请务必在所有匹配项的开头粘贴#{,并在最后添加};

str.replace(r1, '#{<i>$1</i>}')...

会做到这一点。不幸的是,这对我们来说还不够智能 - 我们需要保留与我们的序列(#{...})匹配的项目;换句话说,用自己替换它们。这是一个能够很好地为我们做到这一点的功能:

var replaceFunc = function(match) {
    return match.match(seq)
        ? match
        : '#{<' + this.tag + '>' + match + '</' + this.tag + '>}';
};

然后使用它:

var newStr = str.replace(r1, replaceFunc.bind({tag: 'i'}))
    .replace(r2, replaceFunc.bind({tag: 'h1'}))
    .replace(seq, '$1'); // strip the sequence, leaving the desired string

当然,我知道您在实际实现中不一定会使用HTML标记,但这个顺序可能还不够。但您现在应该可以轻松修改seqreplaceFunc和/或绑定replaceFunc的对象以满足您的需求。

这里是JSFiddle。祝你好运!