Javascript正则表达式 - Lookbehind和lookahead同时

时间:2014-12-08 01:40:00

标签: javascript regex negative-lookahead negative-lookbehind

我正在尝试在JavaScript中创建一个匹配字符b的正则表达式,如果字符a不是之前或之后

显然,JavaScript正则表达式没有容易实现的负面观察,使任务变得困难。我提出了以下一个,但它不起作用。

"ddabdd".replace(new RegExp('(?:(?![a]b(?![a])))*b(?![a])', 'i'),"c");

是我能想到的最好的。在这里,b不应该匹配,因为它前面有a,但它匹配。

关于我想要实现的目标的一些例子

"ddbdd" matches the b
"b" matches the b
"ddb" matches the b
"bdd" matches the b
"ddabdd" or "ddbadd" does not match the b

3 个答案:

答案 0 :(得分:4)

似乎您可以使用包含字符串锚点的开头或“b”之前的否定字符类的捕获组,同时使用Negative Lookahead断言“a”也不会跟随。然后,您只需在替换调用中引用$1以及替换字符串的其余部分。

var s = 'ddbdd b ddb bdd ddabdd ddabdd ddbadd';
var r = s.replace(/(^|[^a])b(?!a)/gi, '$1c');
console.log(r); //=> "ddcdd c ddc cdd ddabdd ddabdd ddbadd"

编辑:由于@nhahtdh指出了关于连续字符的评论,您可以考虑回调。

var s = 'ddbdd b ddb bdd ddabdd ddabdd ddbadd sdfbbfds';
var r = s.replace(/(a)?b(?!a)/gi, function($0, $1) {
    return $1 ? $0 : 'c';
});
console.log(r); //=> "ddcdd c ddc cdd ddabdd ddabdd ddbadd sdfccfds"

答案 1 :(得分:1)

在这种情况下,无法单独使用regex 来模拟后视的行为,因为字符串中可能存在连续的b,这需要零宽度属性一个后视来检查前一个字符。

由于后视中的条件非常简单,您可以在替换功能中检查它:

inputString.replace(/b(?!a)/gi, function ($0, idx, str) {
    if (idx == 0 || !/a/i.test(str[idx - 1])) { // Equivalent to (?<!a)
        return 'c';
    } else {
        return $0; // $0 is the text matched by /b(?!a)/
    }
});

答案 2 :(得分:0)

你真正要做的就是为一种小语言编写一个解析器。 Regexp擅长一些解析任务,但很多很糟糕(而且JS regexp的功能有点不足)。您可能能够找到在特定情况下工作的正则表达式,然后当您的语法规则发生更改时,可能难以或无法更改正则表达式以反映该情况。下面的简单程序具有可读性和可维护性的优点。它完全符合它所说的。

function find_bs(str) {
    var indexes = [];
    for (var i = 0; i < str.length; i++) {
        if (str[i] === 'b' && str[i-1] !== 'a' && str[i+1] !== 'a')
            indexes.push(i);
    }
    return indexes;
}

使用正则表达式

如果您绝对坚持使用正则表达式,则可以使用regexp上的lastIndex属性与RegExp.exec一起重置的技巧:

function find_bs(str) {
    var indexes = [];
    var regexp = /.b[^a]|[^a]b./g;
    var matches;

    while (matches = regexp.exec(str)) {
        indexes.push(matches.index + 1);
        regexp.lastIndex -= 2;
    }

    return indexes;
}

您需要调整逻辑来处理字符串的开头和结尾。

如何运作

我们使用regexp找到整个xbx字符串。 b的索引将是一个加上匹配的索引,因此我们记录下来。在我们进行下一场比赛之前,我们会将lastIndex重置为b,该{{1}}管理搜索将继续的起点,因此它将作为任何后续潜在匹配的第一个字符。< / p>