Ruby 中的条件正则表达式

kst*_*tis 5 ruby regex

我有以下字符串:

'USD 100'
Run Code Online (Sandbox Code Playgroud)

基于这篇文章,我试图捕获100是否USD包含在字符串中单个(货币)字符如果USD不包含在字符串中。

例如:

'USD 100'
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经解决了这个问题,但它不起作用:

https://rubular.com/r/cK8Hn2mzrheHXZ

有趣的是,如果我把USD它放在似乎有效的数量之后。理想情况下,无论货币字符的位置如何,我都希望拥有相同的行为。

Wik*_*żew 3

你的正则表达式(?=.*(USD))(?(1)\d+|[a-zA-Z])不起作用,因为

  • (?=.*(USD))- 正向前瞻,在字符串内的每个位置(如果scan使用的话)触发,该字符串USD与除换行符之外的任何 0 个或更多字符之后的子字符串尽可能多地匹配(这意味着,只有在USD某个位置存在时才会匹配)一条线)
  • (?(1)\d+|[a-zA-Z])- 如果第 1 组匹配(如果有USD),则匹配 1+ 位数字的条件构造,或者将尝试 ASCII 字母。但是,永远不会尝试第二种替代模式,因为您需要USD出现在字符串中才能发生匹配。

查看USD 100 正则表达式调试器(?=.*(USD))(?(1)\d+|[a-zA-Z]),它准确地显示了当正则表达式尝试查找匹配项时会发生什么:

  • 步骤 1 到 22:首先尝试先行模式。这里的要点是,如果正向先行模式未找到匹配项,则匹配将立即失败。在本例中,USD位于字符串的开头(因为第一次尝试该模式,正则表达式索引位于字符串的开头位置)。前瞻找到了匹配项。
  • 步骤23-25:由于前瞻是一种非消耗模式,因此正则表达式索引仍然位于字符串起始位置。前瞻表示“继续”,然后输入条件构造。(?(1)满足条件,组 1, USD, 匹配。因此,第一then部分被触发。\d+找不到任何数字,因为U开头有字母。 正则表达式匹配在字符串起始位置失败,但字符串中还有更多位置需要测试,因为没有\A^锚点只会在字符串/行的开头找到匹配时才会发生匹配。
  • 步骤26:正则表达式引擎索引向右前进一个字符,现在,它位于字母之前S
  • 步骤27-40:正则表达式引擎想要找到0+个字符,然后USD立即找到当前位置的右侧,但失败了(U已经在索引“后面”)。
  • 然后,执行与上面描述的相同:正则表达式无法匹配USD当前位置右侧的任何位置,最终失败。

如果USD位于 右侧的某处100,那么您将得到匹配项

因此,前瞻不会设置任何搜索范围,它只是允许匹配其余模式(如果其模式匹配)或不匹配(如果未找到其模式)

您可以使用

.scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact
Run Code Online (Sandbox Code Playgroud)

图案细节

  • ^USD.*?\K(\d+)- 要么USD在字符串的开头,然后尽可能少地包含除换行符之外的任何 0 个或更多字符,然后删除匹配的文本并将 1+ 位数字捕获到第 1 组中
  • |- 或者
  • ([a-zA-Z])- 捕获到第 2 组中的任何 ASCII 字母。

请参阅Ruby 演示

p "USD 100".scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact
# => ["100"]
p "YEN 100".scan(/^USD.*?\K(\d+)|([a-zA-Z])/).flatten.compact
# => ["Y", "E", "N"]
Run Code Online (Sandbox Code Playgroud)