3

昇順または降順で連続した一連の数字のみで構成されるデータをチェックする方法として、次の正規表現を思い付きました。

明らかな制約: 文字列の長さは 2 ~ 10 桁です。これは、1 桁はシーケンスではなく、10 桁以上を繰り返さなければならないためです。他のコードは、入力が数字だけで構成されていることを保証します。( /\A\d{2,}\z/)

例:

  • '012'、一致する必要が'9876'あります'56'
  • '7''013''6554'および'09'すべきではありません

私はこれが仕事だと思います:

/(?:\A(?:0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)|\d(?!\d)){2,}\z)|
 (?:\A(?:1(?=0)|2(?=1)|3(?=2)|4(?=3)|5(?=4)|6(?=5)|7(?=6)|8(?=7)|9(?=8)|\d(?!\d)){2,}\z)/x

これが質問です: これを Ruby 互換の正規表現で表現するための、より簡潔で美しい方法を見つけられますか?

明らかに、いくつかのネストされたループは、同じ問題に対する正規表現以外のソリューションになります。

if num.length > 1
  [Proc.new { |n| n + 1 }, Proc.new { |n| n - 1 }].each do |p|
    is_sequential = true
    (0..num.length - 2).each do |i|
      if p.call(num[i].ord) != num[i + 1].ord
        is_sequential = false
        break
      end
    end
    return 'Number is sequential' if is_sequential
  end
end

それをより引き締めたり、より美しくしたりしたいですか?

4

7 に答える 7

3
def isseq( s )
  1 < s.length && !!( '0123456789'[s] || '9876543210'[s] )
end

[ '012', '9876', '56', '7', '013', '6554', '09' ].each do |test|
  puts "#{test} #{isseq(test)}"
end

出力:

012 true
9876 true
56 true
7 false
013 false
6554 false
09 false

super_string のアイデアは tihom に、str[s] を使用するのは Tin Man に感謝します。

于 2013-10-23T20:35:25.710 に答える
2
super_string = "0123456789"

'012'.scan(/\d{2,10}/).
map{|x| super_string.include?(x) || super_string.reverse.include?(x) }.
uniq == [true]
#=> true

'013'.scan(/\d{2,10}/).map{|x| super_string.include?(x) || super_string.reverse.include?(x) }.uniq == [true]
#=> false

注: これは、指定された文字列が (10n+1) 桁 (n > 0) で、最後の桁を除くすべての桁が連続している場合に true を返します。それが必要な出力でない場合は、false を返すように変更できます。

于 2013-10-23T20:03:04.540 に答える
2

与えられた最初の数字と文字列の長さに対して、可能な有効な文字列は 2 つだけです。両方を生成して比較するだけです。

def sequential_num(num)

  return false if num =~ /\D/ or num.length <= 1

  initial = num[0]
  range = (num.length - 1)

  final = (initial.ord + range).chr
  return true if final <= '9' and num == (initial..final).to_a.join

  final = (initial.ord - range).chr
  return true if final >= '0' and num == (final..initial).to_a.reverse.join

  return false
end


%w/ 012 9876 56 7 013 6554 09 /.each do |num|
  puts '%-4s %s' % [ num, sequential_num(num) ? 'match' : 'no match' ]
end

出力

012  match
9876 match
56   match
7    no match
013  no match
6554 no match
09   no match
于 2013-10-23T20:33:30.300 に答える
2

ダン、パターン マッチを行うときに、どこに何を配置するかについて考える必要がある場合があります。ここで興味深いのは、'0123456789 9876543210' がすべての可能な正解を含む文字列であることです。入力がすべての数字であり、長さが 1 より大きいことを確認したら、パターン マッチを使用して、データが解の宇宙で発生するかどうかを確認するのが適切です。私は Perl をかなり上手に話せるので、それに固執します。これは一般的なテストです:

長さ>1の数値$nstringも検証されます。

print "$nstring matches!\n" if '0123456789 9876543210' =~ /$nstring/;

または、適切な文字列を監査してからテストする簡単なプログラム:

while (<STDIN>) 
{
    chomp;
    next if not /^[0-9]{2,}$/;
    $nstring=$_;
    $matches='0123456789 9876543210' =~ /$nstring/?"matches":"does not match";
    print "$nstring $matches!\n";
}                                    
于 2013-10-28T18:20:54.570 に答える
2

これは、エリクサーでの非正規表現機能ソリューションの試みです。

#!/usr/bin/env elixir

defmodule Seq do

  def is_seq(list) when match([x, y | t], list), do: is_desc(list) || is_asc(list)
  def is_seq(_), do: false

  def is_desc([first, second | tail]), do: second == first - 1 && is_desc [second | tail]
  def is_desc(_), do: true

  def is_asc([first, second | tail]), do: second == first + 1 && is_asc [second | tail]
  def is_asc(_), do: true

  def test() do
    ['012', '9876', '56', '7', '013', '6554', '09', '012345678', '01234678'] |> Enum.map &is_seq/1
  end
end

Seq.test |> IO.inspect
于 2013-11-05T16:36:43.023 に答える
1

正規表現は、この仕事には良い考えではないと思います。私たちの問題は、「すべての数値の差の絶対値は 1 だけでなければならない」に単純化できます。

irb(main):052:0> s
=> "2345678"
irb(main):053:0> pairs = s.chars.zip(s[1..10].chars).select {|i| i[0] and i[1]}
=> [["2", "3"], ["3", "4"], ["4", "5"], ["5", "6"], ["6", "7"], ["7", "8"]]
irb(main):054:0> pairs.all? {|i| (i[0].to_i - i[1].to_i).abs == 1}
=> true

残りの要件は、 のような簡単なチェックを介して実装できます"23647".chars.uniq!

編集:チェックの必要はありません。セットに繰り返し番号がある場合、主な要件も失敗します。

于 2013-10-23T19:33:52.987 に答える