Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 负先行正则表达式_Javascript_Regex_Regex Lookarounds - Fatal编程技术网

Javascript 负先行正则表达式

Javascript 负先行正则表达式,javascript,regex,regex-lookarounds,Javascript,Regex,Regex Lookarounds,我想匹配所有以“.htm”结尾的字符串,除非它以“foo.htm”结尾。我通常对正则表达式很在行,但负面的表情让我感到困惑。为什么这样不行 /(?!foo)\.htm$/i.test("/foo.htm"); // returns true. I want false. 我应该用什么来代替?我想我需要一个“消极的lookbehind”表达式(如果JavaScript支持这样的东西,我知道它不支持)。您所描述的(您的意图)是消极的lookbehind,JavaScript不支持lookbehi

我想匹配所有以“.htm”结尾的字符串,除非它以“foo.htm”结尾。我通常对正则表达式很在行,但负面的表情让我感到困惑。为什么这样不行

/(?!foo)\.htm$/i.test("/foo.htm");  // returns true. I want false.
我应该用什么来代替?我想我需要一个“消极的lookbehind”表达式(如果JavaScript支持这样的东西,我知道它不支持)。

您所描述的(您的意图)是消极的lookbehind,JavaScript不支持lookbehind

Look aheads从放置它们的角色向前看-您已将其放置在
之前。所以,你实际上说的是“任何以
.htm
结尾的字符,只要以该位置(
.ht
)开头的前三个字符不是
foo
”,这总是正确的

通常情况下,消极落后的替代品是匹配比你需要的更多的东西,并且只提取你真正需要的部分。这是一个骇人听闻的问题,根据您的具体情况,您可能会想出其他方法,但类似的方法如下:

// Checks that the last 3 characters before the dot are not foo:
/(?!foo).{3}\.htm$/i.test("/foo.htm"); // returns false 

如前所述,JavaScript不支持否定的look-behind断言

但您可以使用一种变通方法:

/(foo)?\.htm$/i.test("/foo.htm") && RegExp.$1 != "foo";
这将匹配以
.htm
结尾的所有内容,但如果匹配
foo.htm
,它将
“foo”
存储到
RegExp.$1
,因此您可以单独处理它。

如Renesis所述,“lookback”在JavaScript中不受支持,因此可能只需结合使用两个RegExp:

!/foo\.htm$/i.test(teststring) && /\.htm$/i.test(teststring)

你可以用类似的方法来模拟消极的后顾
/(.|…|.[^f].|.[f[^o].[fo[^o])\.htm$/
,但是编程方法会更好。

问题其实很简单。这可以做到:

/^(?。*foo\.htm$).\.htm$/i
ES6

console.log(/*!(非)endsWith*/
!“foo.html”.endsWith(“foo.htm”),//true
!“barfoo.htm”.endsWith(“foo.htm”),//false(给你)
!“foo.htm”.endsWith(“foo.htm”),//false(给你)
!“test.html”.endsWith(“foo.htm”),//true
!“test.htm”.endsWith(“foo.htm”)//true

);这个答案可能比需要的时间晚了一点,但我会把它留在这里,以防现在有人遇到同样的问题(这个问题提出7年6个月后)

现在,LookBehind已包含在ECMA2018标准中,并且至少在最新版本的Chrome中得到了支持。但是,您可以使用或不使用它们来解决难题

具有负前瞻性的解决方案:

let testString = `html.htm app.htm foo.tm foo.htm bar.js 1to3.htm _.js _.htm`;

testString.match(/\b(?!foo)[\w-.]+\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]
testString.match(/\b(?=[^f])[\w-.]+\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]
具有负后视功能的解决方案:

testString.match(/\b[\w-.]+(?<!foo)\.htm\b/gi);
> (4) ["html.htm", "app.htm", "1to3.htm", "_.htm"]
等等

所有这些正则表达式以不同的方式告诉JS引擎相同的事情,它们传递给JS引擎的消息如下所示

请在此字符串中查找以下所有字符序列:

  • 与其他文本(如文字)分开
  • 由一个或多个英文字母、下划线组成, 连字符、点或数字
  • 以“.htm”结尾
  • 除此之外,.htm之前的序列部分可以是任何内容 但是“福”

不幸的是,JavaScript不支持正则表达式中的“lookbehind”(向后看)。通常最好使用一个简单的正则表达式和一两个循环,而不是一个超级庞然大物(好吧,你想要的不是超级庞然大物,但代码有增长的趋势)需要我说不可维护的正则表达式。这可能不是及时的,但为了解释为什么这不起作用:您的regexp不是0宽度,这意味着在javascript中,它转换为“Match”.htm”,但如果它以“foo”开头,则不会,因为“.htm”永远不会以“foo”开头,这是行不通的。负前瞻的意思是“在这一点上,排除这个负数为真的匹配项”,但它实际上并不消耗字符串。在JavaScript.thx:)中支持前瞻,就像一年前刚刚记住的一样,可能我的记忆没有那么好,你给了我足够的时间让我自己走完剩下的路。这适用于我的所有测试用例:
/(^.{0,2}|)(?!foo.{3})\.htm$/i
+1非常好的解释。但是,
/(?!foo)。{3}\.htm$/i
将无法匹配少于三个字符的名称,即
a.htm
。这里有一个可以得到所有的代码:
/^(?。*foo\.htm$).\.htm$/i
+1。不仅lookbehind不是必需的,如果它可用的话,它也不是最好的工具。这是一种非常有用的技术!你能解释一下发生了什么事吗?我看到您有一个行开始标记(^),但有两个行结束标记($)。这是如何实现负前瞻的?@ericbowden,以防您仍然疑惑:它匹配字符串的开头,而该字符串的结尾不匹配
*foo\.htm
。因为lookaheads没有被消耗,所以它之外的第二个$s实际上是匹配的$s。MDN报告了这一点。