【问题标题】:Ruby Regular expression to find the binary gapRuby正则表达式查找二进制间隙
【发布时间】:2016-10-31 23:05:59
【问题描述】:

我想使用 Ruby 正则表达式找到二进制间隙 说1000001001010011100000000000,左起我想用正则匹配

A. 1000001 应该返回 00000

B. 1001 应该返回 00

C. 101 应该返回 0

D 1001 应该返回 00

我的第一次尝试看起来像这样,但它缺少 B 和 D

更新

正整数 N 中的二进制间隙是在 N 的二进制表示中两端被 1 包围的连续零的任何最大序列。

【问题讨论】:

  • 您能否编辑您的问题以使其易于理解。
  • 什么是“二元差距?你如何定义它?例子 B 和 D 是矛盾的。split('1').compact 会做这项工作吗?

标签: ruby regex


【解决方案1】:

我认为您正在寻找的是:

/1(0+)(?=1)/

您的模式的问题是您消耗了“关闭 1”。结果,下一个研究在这个“结束1”之后开始。 但是,如果您使用前瞻(即不消耗字符且仅测试之后发生的情况的零宽度断言),则不会消耗“关闭 1”并且您会得到所需的结果,因为下一个研究在最后一个零。

请注意,如果您不需要将零括在零之间,您也可以简单地使用:/0+/

其他方式:如果您确定字符串仅包含 1 和 0,您还可以使用(非)字边界断言 \B 与此模式:1\K0++\B

【讨论】:

  • 我正要回答他可能是指需要非捕获组。
  • @Pyrce:小心,非捕获组不会阻止消耗字符。另请参阅,完全不消耗字符的 Cary Swoveland 方式,因为所有内容都包含在前瞻中。使用这种方式,你可以得到所有你想要的重叠子串。
【解决方案2】:
R = /
    (?=     # start a positive lookahead
      1     # match a one
      (0+)  # match one or more zeros in capture group 1
      1     # match a one
    )       # end positive lookahead
    /x      # free-spacting regex definition mode

str = "1000001001010011100000000000"

arr = []
str.scan(R) { |m| arr << [m.first, Regexp.last_match.begin(0)+1] }
arr
  #=> [["00000", 1], ["00", 7], ["0", 10], ["00", 12]] 

arr 的元素对应于str 的一个或多个"0" 的所有子字符串,这些子字符串在1 之前和之后。每对的第一个元素是子字符串,第二个元素是到子字符串开始的str 的偏移量。

这是第二个例子。

str = "10011001010101001110001000100101"

arr = []
str.scan(R) { |m| arr << [m.first, Regexp.last_match.begin(0)+1] }
arr
  #=> [["00", 1], ["00", 5], ["0", 8], ["0", 10], ["0", 12], ["00", 14],
  #    ["000", 19], ["000", 23], ["00", 27], ["0", 30]]

请注意,必须使用正向前瞻,而不是正向后视,因为(在 Ruby 中)后者不允许可变长度字符串(即0+)。

@Stefan 在评论中提出了改进建议:

R = /
    (?<=1) # match a one in a positive lookbehind
    0+     # match one or more zeros
    (?=1)  # match a one in a positive lookahead
    /x      # free-spacting regex definition mode

str = "1000001001010011100000000000"

arr = []
str.scan(R) { |m| arr << [m, Regexp.last_match.begin(0)] }
arr
  #=> [["00000", 1], ["00", 7], ["0", 10], ["00", 12]] 

这类似于@Casimir 建议的 (/1(0+)(?=1)/),不同之处在于通过将第一个 1 放在积极的后视中,不需要捕获组。

这是另一种不使用正则表达式的方法。

str = "1000001001010011100000000000"

(0..str.size-3).each_with_object([]) do |i,a|
  next if str[i] == '0' || str[i+1] == '1'
  ndx = str[i+2..-1].index('1')
  a << [str[i+1, 1+ndx], i+1] if ndx
end
  #=> [["00000", 1], ["00", 7], ["0", 10], ["00", 12]] 

【讨论】:

  • 你不需要懒惰地匹配零,你可以保持贪婪,它们以一为界。
  • 谢谢,@CasimiretHippolyte。最初,我构建了一个哈希,而不是一个数组,其键等于子字符串。我没有得到所有的比赛,很困惑。当我意识到哈希没有重复的键,我当然需要一个数组时,我正在考虑寻求你的帮助。
  • 您也可以使用/(?&lt;=1)0+(?=1)/,而不是将捕获组嵌套在前瞻中。很好的副作用:在 scan 中使用时返回一个平面数组。
  • 谢谢@Stefan。时刻警惕!我从中学到了一些东西。最初,我返回用1 括起来的零字符串,我需要在其中查看整个子字符串。当我决定只返回零时,我想看看我应该如何修改我的答案。我应该回到一张空白纸上,在这种情况下,我可能会看到你的建议。
【解决方案3】:

为了只得到零之间的零,您需要使用正则表达式lookbehind和lookahead:

(?:<=1)0+(?:=1)

之后你只需要获取最大长度元素。

【讨论】:

    猜你喜欢
    • 2021-05-20
    • 2018-11-24
    • 1970-01-01
    • 2012-08-29
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多