Javascript:负向后看等效吗?

2020/11/15 00:22 · javascript ·  · 0评论

有没有办法在javascript正则表达式中实现与否定的后向等效我需要匹配一个不以特定字符集开头的字符串。

如果在字符串的开头找到匹配的部分,我似乎无法找到执行此操作的正则表达式。负向后看似是唯一的答案,但是javascript没有答案。

编辑:这是我想工作的正则表达式,但它不:

(?<!([abcdefg]))m

因此它将与“ jim”或“ m”中的“ m”匹配,但与“ jam”不匹配

后向断言得到了接受ECMAScript规范在2018年。

正向后方用法:

console.log(
  "$9.99  €8.47".match(/(?<=\$)\d+(\.\d*)?/) // Matches "9.99"
);

负向后使用:

console.log(
  "$9.99  €8.47".match(/(?<!\$)\d+(?:\.\d*)/) // Matches "8.47"
);

平台支持:

自2018年以来,Lookbehind Assertions已成为ECMAScript语言规范的一部分

// positive lookbehind
(?<=...)
// negative lookbehind
(?<!...)

回答2018年之前

由于Javascript支持否定先行,一种实现方法是:

  1. 反转输入字符串

  2. 与反向正则表达式匹配

  3. 反转并重新格式化比赛


const reverse = s => s.split('').reverse().join('');

const test = (stringToTests, reversedRegexp) => stringToTests
  .map(reverse)
  .forEach((s,i) => {
    const match = reversedRegexp.test(s);
    console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
  });

范例1:

以下@ andrew-ensley的问题:

test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)

输出:

jim true token: m
m true token: m
jam false token: Ø

范例2:

在@neaumusic注释之后(匹配max-height但不匹配line-height,令牌为height):

test(['max-height', 'line-height'], /thgieh(?!(-enil))/)

输出:

max-height true token: height
line-height false token: Ø

假设您想查找所有int不以unsigned

支持负向后看:

(?<!unsigned )int

不支持负面的后顾之忧:

((?!unsigned ).{9}|^.{0,8})int

基本上,想法是抓住n个前面的字符,并排除具有负前瞻性的匹配,但也要匹配没有前面n个字符的情况。(其中n是向后看的长度)。

所以有问题的正则表达式:

(?<!([abcdefg]))m

将转换为:

((?!([abcdefg])).|^)m

您可能需要与捕获组一起玩,以找到您感兴趣的字符串的确切位置,或者您想用其他东西替换特定部分。

Mijoja的策略适用于您的特定情况,但不适用于一般情况:

js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
   function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]ama

这是一个示例,其目标是匹配双精度1,但如果以“ ba”开头则不匹配。请注意,“ balll”一词-真正的后向应该抑制前两个l,但匹配第二对。但是,通过匹配前2个l,然后忽略该匹配为误报,正则表达式引擎将从该匹配结尾开始,并忽略误报内的任何字符。

使用

newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});

您可以通过否定字符集来定义一个非捕获组:

(?:[^a-g])m

...将与每个m NOT开头的那些字母相匹配

这是我str.split(/(?<!^)@/)为Node.js 8(不支持后向)实现的:

str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()

作品?是的(unicode未经测试)。不愉快?是。

遵循Mijoja的想法,并借鉴JasonS暴露的问题,我有了这个想法;我检查了一下,但不确定自己,所以在js正则表达式中由比我更专业的人进行验证将是很棒的:)

var re = /(?=(..|^.?)(ll))/g
         // matches empty string position
         // whenever this position is followed by
         // a string of length equal or inferior (in case of "^")
         // to "lookbehind" value
         // + actual value we would want to match

,   str = "Fall ball bill balll llama"

,   str_done = str
,   len_difference = 0
,   doer = function (where_in_str, to_replace)
    {
        str_done = str_done.slice(0, where_in_str + len_difference)
        +   "[match]"
        +   str_done.slice(where_in_str + len_difference + to_replace.length)

        len_difference = str_done.length - str.length
            /*  if str smaller:
                    len_difference will be positive
                else will be negative
            */

    }   /*  the actual function that would do whatever we want to do
            with the matches;
            this above is only an example from Jason's */



        /*  function input of .replace(),
            only there to test the value of $behind
            and if negative, call doer() with interesting parameters */
,   checker = function ($match, $behind, $after, $where, $str)
    {
        if ($behind !== "ba")
            doer
            (
                $where + $behind.length
            ,   $after
                /*  one will choose the interesting arguments
                    to give to the doer, it's only an example */
            )
        return $match // empty string anyhow, but well
    }
str.replace(re, checker)
console.log(str_done)

我的个人输出:

Fa[match] ball bi[match] bal[match] [match]ama

原理是checker在字符串中任意两个字符之间的每个点处调用,只要该位置是以下位置的起点:

---任何不需要的大小的子字符串(此处'ba'..)(如果知道该大小,否则可能很难做)

--- ---或更小(如果它是字符串的开头): ^.?

然后,

---实际要查找的内容(在此处'll')。

在每次调用时checker,都会进行测试,以检查之前的值ll是否不是我们不想要的值(!== 'ba');如果是这样,我们将调用另一个函数,并且必须使用这个(doer)才能在str上进行更改,如果目的是这个(或更笼统地说),则将输入必要的数据以进行手动处理扫描的结果str

在这里,我们更改了字符串,因此我们需要跟踪长度的差异,以便偏移所给定的位置replace,这些位置都是在上计算的str,而该位置本身从未改变。

由于原始字符串是不可变的,因此我们可以使用该变量str存储整个操作的结果,但是我认为该示例由于替换而已经很复杂,使用另一个变量(str_done会更清楚

我猜在性能上一定很苛刻:所有无意义地将“”替换为“” this str.length-1,再加上执行者手动替换,这意味着需要大量切片……在上述特定情况下,可能通过仅将字符串切成一小段的方式将其分组,使其围绕我们要插入的位置[match]并与.join()[match]自身对齐。

另一件事是,我不知道它将如何处理更复杂的情况,也就是说,伪造后视的复杂值……长度可能是要获取的最有问题的数据。

并且,在中checker,如果$ behind的非期望值有多种可能性,我们将不得不使用另一个正则表达式(要在外部进行缓存(创建))进行测试checker,以避免生成相同的正则表达式对象在每次调用checker)时都知道它是否是我们想要避免的东西。

希望我已经清楚了;如果不犹豫,我会尽力而为。:)

使用大小写,如果您想替换 m为某些内容,例如将其转换为大写M,则可以否定捕获组中的集合。

匹配([^a-g])m,替换为$1M

"jim jam".replace(/([^a-g])m/g, "$1M")
\\jiM jam

([^a-g])将匹配范围内的任何char not(^a-g,并将其存储在第一个捕获组中,因此您可以使用进行访问$1

因此我们发现imjim,取而代之的是iM其结果jiM

如前所述,JavaScript现在允许回溯。在较旧的浏览器中,您仍然需要解决方法。

我敢打赌,如果没有向后看就能准确地提供结果,就找不到找不到正则表达式的方法。您所能做的就是与小组合作。假设您有一个regex (?<!Before)Wanted,其中Wanted您要匹配Before的正则表达式是,该regex可以计算出不应该匹配的内容。您能做的最好的事情就是取消使用正则表达式Before并使用正则表达式NotBefore(Wanted)期望的结果是第一组$1

就您而言Before=[abcdefg],这很容易被否定NotBefore=[^abcdefg]因此正则表达式将是[^abcdefg](m)如果需要的位置Wanted,则也必须分组NotBefore,以便所需的结果是第二组。

如果Before模式的匹配项具有固定的长度n,也就是说,如果模式不包含重复的标记,则可以避免取反该Before模式并使用正则表达式(?!Before).{n}(Wanted),但是仍然必须使用第一个组或使用正则表达式(?!Before)(.{n})(Wanted)并使用第二个表达式组。在此示例中,图案Before实际上具有固定长度,即1,因此请使用regex(?![abcdefg]).(m)(?![abcdefg])(.)(m)如果您对所有比赛都感兴趣g,请添加标志,请参阅我的代码段:

function TestSORegEx() {
  var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
  var reg = /(?![abcdefg])(.{1})(m)/gm;
  var out = "Matches and groups of the regex " + 
            "/(?![abcdefg])(.{1})(m)/gm in \ns = \"" + s + "\"";
  var match = reg.exec(s);
  while(match) {
    var start = match.index + match[1].length;
    out += "\nWhole match: " + match[0] + ", starts at: " + match.index
        +  ". Desired match: " + match[2] + ", starts at: " + start + ".";   
    match = reg.exec(s);
  }
  out += "\nResulting string after statement s.replace(reg, \"$1*$2*\")\n"
         + s.replace(reg, "$1*$2*");
  alert(out);
}

这有效地做到了

"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null

搜索并替换示例

"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"

请注意,负向后搜索字符串必须为1个字符长,这样才能正常工作。

/(?![abcdefg])[^abcdefg]m/gi
是的,这是一个把戏。

本文地址:http://javascript.askforanswer.com/javascriptfuxianghoukandengxiaoma.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!