我希望这只匹配<style
的第一个实例,因为第二个实例后面的空格具有我放在负前瞻中的模式。
"<style type=\"text/html\">ciaoxocs <style />".scan /<style\s?(?!\/>)/
# => ["<style ", "<style"]
我想解释一下这里发生了什么,并且可能是一个更好的解决方案,只匹配第一个实例,而不使用或不使用空格匹配结束标记:
<style /> or <style/>
在regex101.com中,它与其他语言一样正常工作:
答案 0 :(得分:2)
问题来自回溯机制。让我们看一下结束标记会发生什么的描述:
<script\s?
匹配"<script "
,但(?!/>)
失败。在这种情况下,回溯机制开始,量词一个接一个地返回它们的字符,直到模式成功。在我们的例子中,唯一的可能性是从\s?
返回空间
在此回溯步骤之后,<script\s?
匹配"<script"
(此时没有空格),(?!/>)
条件与" />"
成功。
有几种方法可以阻止这种机制:
(?>...)
(一旦达到右括号,禁止回溯子模式):<script(?>\s?)(?!/>)
?+
(禁止对量词进行回溯):<script\s?+(?!/>)
<script(?!\s?/>)\s?
答案 1 :(得分:1)
请注意,第二个匹配(来自<style />
)是<style
,(没有空格)而不是<style
(以空格结尾;不知何故,你看不出这里的区别)。 (?!\/>)
中的否定前瞻/<style\s?(?!\/>)/
仅禁止\/>
在匹配<style\s?
的子字符串后出现。如果与正则表达式的这一部分对应的匹配字符串是<style
(没有空格),那么原始字符串中紧跟其后的是空格(而不是\/>
),因此负面条件很满意。
如果您确定要匹配的模式总是有空格,那么您可以简单地设置空间,并且您将只获得您想要的空间:
"<style type=\"text/html\">ciaoxocs <style />".scan /<style\s(?!\/>)/
# => ["<style "]
如果您无法确定,请将可选空间移至否定前瞻。
"<style type=\"text/html\">ciaoxocs <style />".scan /<style(?!\s?\/>)/
# => ["<style"]
答案 2 :(得分:-2)
您可能希望使用String#match
而不是String#scan
,它会迭代地应用模式,直到到达字符串结尾。
> "<style type=\"text/html\">ciaoxocs <style />".match(/<style\s?(?!\/>)/).to_a
=> ["<style "]