189

What the best way to find if a string starts with another in Ruby (without rails)?

David Hempy
  • 5,373
  • 2
  • 40
  • 68
Guillaume Coté
  • 2,761
  • 2
  • 21
  • 28

4 Answers4

303
puts 'abcdefg'.start_with?('abc')  #=> true

[edit] This is something I didn't know before this question: start_with? takes multiple arguments.

'abcdefg'.start_with?( 'xyz', 'opq', 'ab')
Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
steenslag
  • 79,051
  • 16
  • 138
  • 171
  • 1
    MRI 1.8.7 does not have `start_with?`, but MRI 1.9 does, as does Rails. – Wayne Conrad Nov 12 '10 at 21:18
  • @Wayne Conrad: Strangely, 1.8.7 *does* have the documentation for [`String#start_with?`](http://RubyDoc.Info/docs/ruby-core/1.8.7/String#start_with%3F-instance_method). – Jörg W Mittag Nov 13 '10 at 02:45
  • @Jörg W Mittag, perhaps not strangely, I was wrong. MRI 1.8.7 does indeed have `start_with?`. I guess I typo'd it when I loaded up irb to try it. – Wayne Conrad Nov 13 '10 at 04:13
  • 9
    Interestingly, Rails defines the grammaticaly correct `starts_with?`, which in 1.8.7 and above is just aliased to `start_with?`. – Mark Thomas Nov 13 '10 at 14:57
64

Since there are several methods presented here, I wanted to figure out which one was fastest. Using Ruby 1.9.3p362:

irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> Benchmark.realtime { 1.upto(10000000) { "foobar"[/\Afoo/] }}
=> 12.477248
irb(main):003:0> Benchmark.realtime { 1.upto(10000000) { "foobar" =~ /\Afoo/ }}
=> 9.593959
irb(main):004:0> Benchmark.realtime { 1.upto(10000000) { "foobar"["foo"] }}
=> 9.086909
irb(main):005:0> Benchmark.realtime { 1.upto(10000000) { "foobar".start_with?("foo") }}
=> 6.973697

So it looks like start_with? ist the fastest of the bunch.

Updated results with Ruby 2.2.2p95 and a newer machine:

require 'benchmark'
Benchmark.bm do |x|
  x.report('regex[]')    { 10000000.times { "foobar"[/\Afoo/] }}
  x.report('regex')      { 10000000.times { "foobar" =~ /\Afoo/ }}
  x.report('[]')         { 10000000.times { "foobar"["foo"] }}
  x.report('start_with') { 10000000.times { "foobar".start_with?("foo") }}
end

            user       system     total       real
regex[]     4.020000   0.000000   4.020000 (  4.024469)
regex       3.160000   0.000000   3.160000 (  3.159543)
[]          2.930000   0.000000   2.930000 (  2.931889)
start_with  2.010000   0.000000   2.010000 (  2.008162)
haslo
  • 1,030
  • 2
  • 12
  • 23
  • 4
    not surprising given compiling and testing for regular expressions is much harder then simply comparing bytes – akostadinov Nov 05 '14 at 15:53
  • 1
    It should be noted that Regex is far superior for case insensitive searches, even if you calculated all the permutations of cases for the test string ahead of time. – Peter P. Apr 02 '15 at 23:03
  • 4
    @PeterP. I just tested case insensitive searches, and start_with? still comes out ahead if you just downcase the string to search and then compare with the lowercase search string: `"FooBar".downcase.start_with?("foo")`. – haslo May 04 '16 at 09:20
5

The method mentioned by steenslag is terse, and given the scope of the question it should be considered the correct answer. However it is also worth knowing that this can be achieved with a regular expression, which if you aren't already familiar with in Ruby, is an important skill to learn.

Have a play with Rubular: http://rubular.com/

But in this case, the following ruby statement will return true if the string on the left starts with 'abc'. The \A in the regex literal on the right means 'the beginning of the string'. Have a play with rubular - it will become clear how things work.

'abcdefg' =~  /\Aabc/ 
pakeha
  • 2,480
  • 3
  • 22
  • 24
  • As pointed out by Wayne Conrad, this method will also work on a wider variety of runtimes than start_with will. – pakeha Nov 12 '10 at 21:43
2

I like

if ('string'[/^str/]) ...
the Tin Man
  • 158,662
  • 42
  • 215
  • 303