如何在Ruby Regex中正确使用前瞻?

时间:2015-10-01 12:30:14

标签: ruby regex

我希望这只匹配<style的第一个实例,因为第二个实例后面的空格具有我放在负前瞻中的模式。

"<style type=\"text/html\">ciaoxocs <style />".scan /<style\s?(?!\/>)/
# => ["<style ", "<style"]

我想解释一下这里发生了什么,并且可能是一个更好的解决方案,只匹配第一个实例,而不使用或不使用空格匹配结束标记:

<style /> or <style/>

在regex101.com中,它与其他语言一样正常工作:

https://www.regex101.com/r/pW2oM3/1

3 个答案:

答案 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 "]