Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/401.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 在IE中返回值的正则表达式在Firefox和Safari/Chrome中为“未定义”_Javascript_Regex_Internet Explorer_Exec - Fatal编程技术网

Javascript 在IE中返回值的正则表达式在Firefox和Safari/Chrome中为“未定义”

Javascript 在IE中返回值的正则表达式在Firefox和Safari/Chrome中为“未定义”,javascript,regex,internet-explorer,exec,Javascript,Regex,Internet Explorer,Exec,有一个正则表达式: .*? (rule1|rule2) (?:(rule1|rule2)|[^}])* 它被设计用来解析CSS文件,而“规则”是由JS生成的 当我在IE中尝试此功能时,一切都正常工作。 在RegexBuddy或Regex Coach中尝试时也是如此 但当我在Firefox或Chrome中尝试时,结果是缺少值。 有谁能解释一下真正的浏览器在想什么,或者我是如何获得类似IE的结果的 若要查看实际情况,请加载一个提供交互式测试的页面,例如W3Schools试用编辑器 以下是可以粘贴的

有一个正则表达式:

.*?
(rule1|rule2)
(?:(rule1|rule2)|[^}])*
它被设计用来解析CSS文件,而“规则”是由JS生成的

当我在IE中尝试此功能时,一切都正常工作。 在RegexBuddy或Regex Coach中尝试时也是如此

但当我在Firefox或Chrome中尝试时,结果是缺少值。 有谁能解释一下真正的浏览器在想什么,或者我是如何获得类似IE的结果的

若要查看实际情况,请加载一个提供交互式测试的页面,例如W3Schools试用编辑器

以下是可以粘贴的源:

以下是Firefox和Chrome中的输出:

0: #rot { rule1; rule2; 
1: rule1
2: undefined
当我使用string.match尝试相同的方法时,我会在所有浏览器(包括IE)中返回一个未定义的数组

var str="#rot { rule2; rule1; rule2; }";
var patt=/.*?(rule1|rule2)(?:(rule1|rule2)|[^}])*/gi;
var result=str.match(patt);
for(var i = 0; i < 5; i++) document.write(i+": "+result[i]+"<br>"); 
这是怎么回事?! 我尝试过的所有其他字符串都会产生第一组非捕获。 非常感谢您的帮助

编辑: 根据马修的建议,代码已经缩短,并且投入了许多小时的研究。 标题已更改,以便更容易找到该线程

我认为马修的答案是正确的,因为它经过了充分的研究和描述。 在马修修改他的逻辑之前,我在下面的回答中用更简单、更直接的术语陈述了逻辑。

试着删除上面正则表达式第4行和第5行前面的?:吧。我还没有测试过,但看起来它们真的不属于那里

(?:^|})
([^{]+)
[^}]+?-moz-
((transform[^-][^;}]+)|(transform-origin[^;}]+))
(-moz-(?:(transform[^-][^;}]+)|(transform-origin[^;}]+))|[^}])*

我错了。在ECMAScript中,只有一个选项可以生成字符串。所有其他的都必须是未定义的,而不是其他的

因此,对于您的备选方案,包括transform[^-][^;}]+| transform origin[^;}]+,Firefox和Chrome将失败捕获设置为undefined是正确的

ECMAScript 5标准§15.10.2.3中有一个具体的例子:

请注意|正则表达式运算符 将两个备选方案分开。这个 模式首先尝试匹配左侧 《另类》的续集 正则表达式;如果失败了,, 它试图与右边的匹配 析取后接续集 正则表达式。如果左边 另一种选择,右边的析取, 续集都有选择点, 续集中的所有选择都经过了尝试 在转到中的下一个选项之前 左派选择。如果选择 左派的选择已经用尽了, 而是尝试右析取 左派的选择。任何捕获 括号中的一部分 被|生成未定义的模式跳过 值而不是字符串

因此 例如,/a | ab/.execabc返回 结果是a而不是ab。此外, /a | abc | bc/.execabc 返回数组[abc,a,a, 未定义,bc,未定义,bc]和 非[abc,ab,未定义,ab, c、 c,未定义]

编辑:我算出了最后一部分。这适用于原始版本和简化版本。在这两种情况下,规则1和规则2都不能匹配;原来是因为;在否定字符类[^;}]中。因此,;在声明之间点击,交替选择[^}]。因此,它必须将最后两次捕获设置为未定义

对于完全贪婪的人来说,最后一个;输入中的空格也必须匹配。对于最后两个*重复';'和“”,交替再次选择[^}],因此捕获也应在末尾设置为未定义

IE在这两种情况下都无法做到这一点,因此它们与规则1和规则2保持一致

最后,第二个示例行为不同的原因是transform origin[^;}]+在最后一次*重复时匹配,因为没有;在结束之前

编辑2:我将详细介绍当前两个示例应该发生的事情。match是匹配数组

var str="#rot { rule1; rule2; }";
var patt=/.*?(rule1|rule2)(?:(rule1|rule2)|[^}])*/i;

.*? - "#rot { "

(rule1|rule2) - "rule1"
match[1] = "rule1"
星1

[^}] - ";"
match[2] = undefined 
[^}] - ";"
match[2] = undefined 
明星2

[^}] - " "
match[2] = undefined 
[^}] - " "
match[2] = undefined 
明星3

(rule1|rule2) - "rule2"
match[2] = "rule2"
(rule1 |rule2 ) - "rule2 "
match[2] = "rule2 "
明星4

[^}] - ";"
match[2] = undefined 
明星5

[^}] - " "
match[2] = undefined 
同样,IE没有将match[2]设置为undefined

对于str.match示例,您使用的是全局标志。这意味着它返回一个匹配数组,不包含捕获。这适用于任何使用。如果使用g,则必须使用exec来获取捕获

var str="#rot { rule1; rule2 }";
var patt=/.*?(rule1|rule2)(?:(rule1 |rule2 )|[^}])*/gi;

.*? - "#rot { "
(rule1|rule2) - "rule1"
match[1] = "rule1"
星1

[^}] - ";"
match[2] = undefined 
[^}] - ";"
match[2] = undefined 
明星2

[^}] - " "
match[2] = undefined 
[^}] - " "
match[2] = undefined 
明星3

(rule1|rule2) - "rule2"
match[2] = "rule2"
(rule1 |rule2 ) - "rule2 "
match[2] = "rule2 "

因为这是最后一个*,所以捕获永远不会被设置为未定义。

您的第四个和第五个模式正在竞争。最终由浏览器正则表达式引擎的实现来确定匹配项。这并不是IE和其他人的第一个区别

(?:(transform[^-][^;}]+)|(transform-origin[^;}]+))
(?:-moz-(?:(transform[^-][^;}]+)|(transform-origin[^;}]+))|[^}])*
这两者都以transform作为前缀,以origin作为后缀。你需要把这些浓缩成一个更简洁的表达。下面是一个例子:

((?:-moz-)?(?:transfrom-origin[^;}]+))

如何处理重复捕获括号存在分歧

Firefox和Webkit都做出了以下假设,即只做出了第一个假设:

如果重复使用括号,每次捕获新内容时,只存储最后一个结果。 如果圆括号位于较大的非捕获重复圆括号内,并且没有捕获最后一个循环中的任何内容,则圆括号应为captur 没什么。 例如:

var str = 'abcdef';
var pat = /([a-f])+/;
pat.exec将捕获一个“a”,然后用“b”等替换它,直到它返回一个“f”。 在所有浏览器中

var str = 'abcdefg';
var pat = /(?:([a-f])|g)+/;
pat.exec将首先在捕获括号中填入“a”、“b”到“f”。 但非捕获父对象将继续并匹配“g”。在此期间,捕获括号中没有任何内容,因此它被清空。 正则表达式将返回一个未定义的字符串作为其响应

IE认为捕获括号在最后一个循环throup中没有捕获任何内容,因此使用最后一个有效响应“f”

这是有用的,但不符合逻辑

不合逻辑地有用比有用更具破坏性。我们都讨厌怪癖。
Advantage Firefox/Chrome。

可以简化测试用例,例如:

/^(?:(Foo)|Bar)(?:(Foo)|Bar)/.exec("FooBar") // => [ 'FooBar', 'Foo' ]
/^(?:(Foo)|Bar){2}/.exec("FooBar")           // => [ 'FooBar', undefined ]
这里唯一的区别是?:Foo |条在第二种情况下由a重复,这导致其捕获被清除

该行为由以下条款规定:

RepeatMatcher的第4步在每次重复Atom时清除Atom的捕获

IE与本规范的偏差也是:

ES3声明,RepeatMatcher的步骤4在每次原子被重复时清除原子的捕获

JScript不会在每次原子重复时清除原子的匹配项

值得注意的是,ES规范与其他正则表达式引擎的行为不一致,它们的行为通常类似于IE:

火狐浏览器
"FooBar".match(/^(?:(Foo)|Bar)*/)[1] // => undefined
Perl python 红宝石
我建议您尝试将其压缩为一个更小、更简单的示例,该示例仍然显示出相同的差异。您甚至可以在这个过程中解决问题。完成。更奇怪的是,更小的代码比原来的代码更不一致。这意味着他不想捕获它。我知道这就是它的意思。看起来它应该捕捉到这一点。它们是有意的,但我删除了它们,并大大简化了示例,就像在问题中,它只是噪音。请再看一看,我很生气!请支持你的论点,即标准允许未定义的行为。@Matthew,我已经从我的答案中删除了未定义的行为,因为我同意这可能是误导。尽管如此,我相信这至少是老年退休金计划问题的一部分。在回顾了你的答案之后,你似乎有着同样的信念。我也不认为这取决于实施。我只是觉得IE有一个bug。这两个规则只是两个CSS规则的一个糟糕的例子。它们不能被浓缩。请参阅问题的修复,我将示例简化了很多。不过,这两种模式并不相互竞争——它应该抓住第一种模式,然后再抓住第二种模式。注意正则表达式开头的惰性量词。这个正则表达式在我使用的每个正则表达式工具中都能很好地工作,包括语言设置为JS@Matthew,相当批评我的措辞@SamGoody,抱歉,但我仍然保持转换[^-][^;}]+|转换原点[^;}]+这两个都捕获了转换原点:somevalue。所以他们在竞争。这很好,虽然我真的不在乎回答是未定义的还是空的,但我很在乎应该捕获的结果不被忽略。谢谢,但我认为这不管用。虽然;在否定字符类中,捕获括号应通过捕获-但不包括分号。贪婪的明星也是如此。如果您尝试使用当前的简化示例,您将看到后一个括号没有捕获任何内容,即使您从字符串中删除了右大括号,并允许捕获一直进行到结尾。@Sam,它捕获不包括分号,但捕获稍后会被取消定义。我已经浏览了上面的前三个示例。顺便说一句,因为我们使用了这么多的示例,所以为它们提供唯一的变量名会有助于避免混淆。是的,Firefox和Chrome符合模式中被|跳过的部分中的任何捕获括号,生成未定义的值而不是字符串。见上面的标准引文。
"FooBar"[/^(?:(Foo)|Bar)*/, 1] # => "Foo"