为什么范围的正则表达式失败?

时间:2015-06-19 17:03:13

标签: ruby regex

目的是创建一个正则表达式,用于解析给定字符串中的包含(..)和独占(...)范围。

我的边缘案例如下:

  1. 范围的initialfinal值不能包含空格。
  2. 仅接受包容性(..)和排他性(...)范围。
  3. final值在开头不能包含点(.)。
  4. 整个字符串应该是有效范围。
  5. 也就是说,一个范围无效的字符串将是:

    • "1 2..20""1 2...20""12..2 0"
    • "1....10"" 1.10`

    这是我到目前为止的正则表达式

    /\A([^.\s]+)(\.{2,3})([^.][^\s]+)\z/

    然而它失败了。似乎原因是第三个捕获组中的[^.]部分。如果没有[^.],它的效果非常好,但不幸的是并未涵盖所有情况。

    我正在使用Ruby 2.2.1。

2 个答案:

答案 0 :(得分:2)

尝试

/\A([^\s]*[^.])(\.{2,3})([^.][^\s]*)\z/

这使用*代替+,以便允许第三个捕获组只捕获一个字符(您之前的表达式要求它捕获至少两个字符)。

答案 1 :(得分:0)

这将允许您确定字符串是否表示有效的整数或日期对象范围,如果是,则返回范围。

<强>代码

R = /
    \A        # match beginning of string
    (.+?)     # match one or more characters lazily in capture group 1
    (\.{2,3}) # match 2 or 3 dots in capture group 2
    ([^.]+)   # match any characters other than dot in capture group 3
    \z        # match end of string
    /x        # extended mode

require 'date'

def convert_to_range(str)
  str[R]
  return nil unless $1
  e1 = $1.strip
  e2 = $3.strip
  exclude_end = ($2.size == 3)
  return nil if e1[/\s/] || e2[/\s/]

  # Range of integers?   
  return rng(e1.to_i, e2.to_i, exclude_end) if e1[/\A\d+\z/] && e2[/\A\d+\z/]

  # Range of dates?   
  begin
    d1 = Date.parse(e1)
    d2 = Date.parse(e2)
    return rng(d1, d2, exclude_end)
  rescue ArgumentError
  end

  nil
end

def rng(e1,e2,exclude_end)
  Range.new(e1, e2, exclude_end)
end

<强>实施例

convert_to_range " 1 .. 20 "
  #=> 1..20 
convert_to_range "1...20"
  #=> 1...20 
convert_to_range "20..1"
  #=> 20..1
convert_to_range("20..1").size
  #=> 0
convert_to_range "1 2..20"
  #=> nil
convert_to_range "1 2...20"
  #=> nil
convert_to_range "12..2 0"
  #=> nil
convert_to_range "1....10"
  #=> nil
convert_to_range "1.10"
  #=> nil
convert_to_range "1.10"
  #=> nil

convert_to_range "2015-06-10...2015-06-19"
  #=> #<Date: 2015-06-10 ((2457184j,0s,0n),+0s,2299161j)>...
  #   #<Date: 2015-06-19 ((2457193j,0s,0n),+0s,2299161j)> 
convert_to_range "2015-06-19...2015-06-10"
  #=> #<Date: 2015-06-19 ((2457193j,0s,0n),+0s,2299161j)>...
  #   #<Date: 2015-06-10 ((2457184j,0s,0n),+0s,2299161j)> 
convert_to_range "2015-06-10...cat"
  #=> nil