2

StringRuby on Rails 3.2.9 を使用しており、名前の最初の文字 (a ) が数字 ( ) ではないことを検証したいと考えていIntegerます。次のコードを使用しようとしています。

class User < ActiveRecord::Base
  validates_each :name do |record, attr, value|
    record.errors.add(attr, 'cannot begin with a number') if ... # the first char is a number
  end
end

どうすればそれを作ることができますか?

4

4 に答える 4

6
record.errors.add(attr, 'cannot begin with a number') if value =~ /^[0-9].*/

最初の文字が数字である任意の文字列に一致します

于 2012-12-15T12:33:24.570 に答える
3

答えを見ると、テストにはさまざまな方法がありました。魔法のように速くなるのではないかと思う人もいたので、いつものように、ベンチマークを行いました。

require 'benchmark'

puts "Ruby = #{ RUBY_VERSION }"
str = 'foobar'

puts 'correct result should be false...'
puts !!( str =~ /^\d/                           )
puts !!( str =~ /\A\d/                          )
puts !!( str =~ /^[0-9].*/                      )
puts !!( str.split('').first.to_i.is_a?(Fixnum) )
puts !!( (48..57).include?(str[0])              )

puts !!( ('0'..'9') === str[0]                  )
puts !!( str[/^\d/]                             )
puts !!( str[/\A\d/]                            )
puts !!( str[/\A[0-9]/]                         )
puts !!( str =~ /\A[0-9]/                       )

puts

n = 1_000_000

puts "n = 1_000_000"
puts "str = 'foobar'"
Benchmark::bm(17) do |b|
  b.report('^\d regex')         { n.times { str =~ /^\d/                           } }
  b.report('\A\d regex')        { n.times { str =~ /\A\d/                          } }
  b.report('^[0-9].* regex')    { n.times { str =~ /^[0-9].*/                      } }
  b.report('start_with?')       { n.times { str.start_with?(*('0'..'9'))           } }
  b.report("split('')")         { n.times { str.split('').first.to_i.is_a?(Fixnum) } }
  b.report("(48..57).include?") { n.times { (48..57).include?(str[0])              } }

  b.report('range')           { n.times { ('0'..'9') === str[0] } }
  b.report('str[/^\d/]')      { n.times { str[/^\d/]            } }
  b.report('str[/\A\d/]')     { n.times { str[/\A\d/]           } }
  b.report('str[\A[0-9]')     { n.times { str[/\A[0-9]/]        } }
  b.report('\A[0-9] regex')   { n.times { str =~ /\A[0-9]/      } }
end

puts

str = 'foobar' * 1000
puts "str = 'foobar' * 1000"
Benchmark::bm(17) do |b|
  b.report('^\d regex')         { n.times { str =~ /^\d/                 } }
  b.report('\A\d regex')        { n.times { str =~ /\A\d/                } }
  b.report('^[0-9].* regex')    { n.times { str =~ /^[0-9].*/            } }
  b.report('start_with?')       { n.times { str.start_with?(*('0'..'9')) } }
  b.report("(48..57).include?") { n.times { (48..57).include?(str[0])    } }

  b.report('range')           { n.times { ('0'..'9') === str[0] } }
  b.report('str[/^\d/]')      { n.times { str[/^\d/]            } }
  b.report('str[/\A\d/]')     { n.times { str[/\A\d/]           } }
  b.report('str[\A[0-9]')     { n.times { str[/\A[0-9]/]        } }
  b.report('\A[0-9] regex')   { n.times { str =~ /\A[0-9]/      } }
end

試験結果:

Ruby = 1.9.3
correct result should be false...
false
false
false
true
false
false
false
false
false
false

ベンチマーク結果:

n = 1_000_000
str = 'foobar'
                        user     system      total        real
^\d regex           0.590000   0.000000   0.590000 (  0.593534)
\A\d regex          0.560000   0.000000   0.560000 (  0.556304)
^[0-9].* regex      0.580000   0.000000   0.580000 (  0.577662)
start_with?         4.020000   0.000000   4.020000 (  4.025604)
split('')           6.850000   0.000000   6.850000 (  6.872157)
(48..57).include?  17.260000   0.780000  18.040000 ( 18.038887)
range               1.260000   0.000000   1.260000 (  1.258191)
str[/^\d/]          0.680000   0.000000   0.680000 (  0.680291)
str[/\A\d/]         0.660000   0.000000   0.660000 (  0.663305)
str[\A[0-9]         0.670000   0.000000   0.670000 (  0.670242)
\A[0-9] regex       0.570000   0.000000   0.570000 (  0.574152)

\A長い文字列よりも速いかどうかをテスト^し、どのような効果があるかを確認するために、文字列のサイズを大きくしました。 "split('')"60秒以上経過しても完了しなかったためにプルされました:

str = 'foobar' * 1000
                        user     system      total        real
^\d regex          15.010000   0.000000  15.010000 ( 15.020488)
\A\d regex          0.540000   0.010000   0.550000 (  0.539736)
^[0-9].* regex     15.000000   0.000000  15.000000 ( 15.011137)
start_with?         4.010000   0.000000   4.010000 (  4.010340)
(48..57).include?  17.320000   0.770000  18.090000 ( 18.124795)
range               1.250000   0.000000   1.250000 (  1.255724)
str[/^\d/]         15.120000   0.010000  15.130000 ( 15.142242)
str[/\A\d/]         0.650000   0.000000   0.650000 (  0.656198)
str[\A[0-9]         0.650000   0.000000   0.650000 (  0.652306)
\A[0-9] regex       0.550000   0.000000   0.550000 (  0.544415)

1.8.7で再テストしました:

Ruby = 1.8.7
correct result should be false...
false
false
false
true
false
false
false
false
false
false

n = 1_000_000
str = 'foobar'
                       user     system      total        real
^\d regex          0.570000   0.000000   0.570000 (  0.565397)
\A\d regex         0.550000   0.000000   0.550000 (  0.552270)
^[0-9].* regex     0.570000   0.000000   0.570000 (  0.574705)
start_with?       38.180000   0.070000  38.250000 ( 39.864171)
split('')          9.750000   0.040000   9.790000 ( 11.025962)
(48..57).include?  0.580000   0.000000   0.580000 (  0.917499)
range              2.420000   0.020000   2.440000 (  3.170774)
str[/^\d/]         0.700000   0.000000   0.700000 (  0.760180)
str[/\A\d/]        0.680000   0.000000   0.680000 (  0.762636)
str[\A[0-9]        0.660000   0.010000   0.670000 (  0.795043)
\A[0-9] regex      0.600000   0.000000   0.600000 (  0.684566)

str = 'foobar' * 1000
                       user     system      total        real
^\d regex          7.900000   0.040000   7.940000 ( 10.735175)
\A\d regex         0.600000   0.010000   0.610000 (  0.784001)
^[0-9].* regex     7.850000   0.020000   7.870000 (  8.251673)
(48..57).include?  0.580000   0.000000   0.580000 (  0.683730)
range              2.380000   0.020000   2.400000 (  2.738234)
str[/^\d/]         7.930000   0.010000   7.940000 (  8.227906)
str[/\A\d/]        0.670000   0.000000   0.670000 (  0.682169)
str[\A[0-9]        0.680000   0.000000   0.680000 (  0.697340)
\A[0-9] regex      0.580000   0.000000   0.580000 (  0.645136)

自分たちの間で話し合います。

于 2012-12-15T16:04:05.960 に答える
1

範囲をスプラットできることがわかりました:

"1hello".start_with?(*('0'..'9')) #=> true
于 2012-12-15T15:13:54.733 に答える
0

配列アクセスを使用して文字列の最初の文字を取得し、ASCII 値を比較できます。

1.8.7 :008 > (48..57).include?("5ssdfsdf"[0])
 => true 
1.8.7 :009 > (48..57).include?("ssdfsdf"[0])
 => false 
1.8.7 :010 > (48..57).include?("0sdfsdf"[0])
 => true 
1.8.7 :011 > (48..57).include?("9sdfsdf"[0])
 => true 
于 2012-12-15T16:06:49.617 に答える