Какой самый простой способ удалить первый символ из строки?

Пример:

[12,23,987,43

Какой самый быстрый и эффективный способ удалить "[", используя, возможно, chop(), но для первого символа?

Ответ 1

Я предпочитаю использовать что-то вроде:

asdf = "[12,23,987,43"
asdf[0] = '' 

p asdf
# >> "12,23,987,43"

Я всегда ищу самый быстрый и читаемый способ делать вещи:

require 'benchmark'

N = 1_000_000

puts RUBY_VERSION

STR = "[12,23,987,43"

Benchmark.bm(7) do |b|
  b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
  b.report('sub') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }

  b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
  b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
  b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
  b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }

end

Работа на моем Mac Pro:

1.9.3
              user     system      total        real
[0]       0.840000   0.000000   0.840000 (  0.847496)
sub       1.960000   0.010000   1.970000 (  1.962767)
gsub      4.350000   0.020000   4.370000 (  4.372801)
[1..-1]   0.710000   0.000000   0.710000 (  0.713366)
slice     1.020000   0.000000   1.020000 (  1.020336)
length    1.160000   0.000000   1.160000 (  1.157882)

Обновление, чтобы включить еще один предложенный ответ:

require 'benchmark'

N = 1_000_000

class String
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end

  def first(how_many = 1)
    self[0...how_many]
  end

  def shift(how_many = 1)
    shifted = first(how_many)
    self.replace self[how_many..-1]
    shifted
  end
  alias_method :shift!, :shift
end

class Array
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end
end

puts RUBY_VERSION

STR = "[12,23,987,43"

Benchmark.bm(7) do |b|
  b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
  b.report('sub') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }

  b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
  b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
  b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
  b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }
  b.report('eat!') { N.times { "[12,23,987,43".eat! } }
  b.report('reverse') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end

Результат:

2.1.2
              user     system      total        real
[0]       0.300000   0.000000   0.300000 (  0.295054)
sub       0.630000   0.000000   0.630000 (  0.631870)
gsub      2.090000   0.000000   2.090000 (  2.094368)
[1..-1]   0.230000   0.010000   0.240000 (  0.232846)
slice     0.320000   0.000000   0.320000 (  0.320714)
length    0.340000   0.000000   0.340000 (  0.341918)
eat!      0.460000   0.000000   0.460000 (  0.452724)
reverse   0.400000   0.000000   0.400000 (  0.399465)

И еще с помощью /^./, чтобы найти первый символ:

require 'benchmark'

N = 1_000_000

class String
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end

  def first(how_many = 1)
    self[0...how_many]
  end

  def shift(how_many = 1)
    shifted = first(how_many)
    self.replace self[how_many..-1]
    shifted
  end
  alias_method :shift!, :shift
end

class Array
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end
end

puts RUBY_VERSION

STR = "[12,23,987,43"

Benchmark.bm(7) do |b|
  b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
  b.report('[/^./]') { N.times { "[12,23,987,43"[/^./] = '' } }
  b.report('[/^\[/]') { N.times { "[12,23,987,43"[/^\[/] = '' } }
  b.report('sub+') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }
  b.report('sub') { N.times { "[12,23,987,43".sub(/^\[/, "") } }
  b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
  b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
  b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
  b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }
  b.report('eat!') { N.times { "[12,23,987,43".eat! } }
  b.report('reverse') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end

Результат:

# >> 2.1.5
# >>               user     system      total        real
# >> [0]       0.270000   0.000000   0.270000 (  0.270165)
# >> [/^./]    0.430000   0.000000   0.430000 (  0.432417)
# >> [/^\[/]   0.460000   0.000000   0.460000 (  0.458221)
# >> sub+      0.590000   0.000000   0.590000 (  0.590284)
# >> sub       0.590000   0.000000   0.590000 (  0.596366)
# >> gsub      1.880000   0.010000   1.890000 (  1.885892)
# >> [1..-1]   0.230000   0.000000   0.230000 (  0.223045)
# >> slice     0.300000   0.000000   0.300000 (  0.299175)
# >> length    0.320000   0.000000   0.320000 (  0.325841)
# >> eat!      0.410000   0.000000   0.410000 (  0.409306)
# >> reverse   0.390000   0.000000   0.390000 (  0.393044)

Вот еще одно обновление более быстрого оборудования и более новой версии Ruby:

2.3.1
              user     system      total        real
[0]       0.200000   0.000000   0.200000 (  0.204307)
[/^./]    0.390000   0.000000   0.390000 (  0.387527)
[/^\[/]   0.360000   0.000000   0.360000 (  0.360400)
sub+      0.490000   0.000000   0.490000 (  0.492083)
sub       0.480000   0.000000   0.480000 (  0.487862)
gsub      1.990000   0.000000   1.990000 (  1.988716)
[1..-1]   0.180000   0.000000   0.180000 (  0.181673)
slice     0.260000   0.000000   0.260000 (  0.266371)
length    0.270000   0.000000   0.270000 (  0.267651)
eat!      0.400000   0.010000   0.410000 (  0.398093)
reverse   0.340000   0.000000   0.340000 (  0.344077)

Почему gsub настолько медленный?

После выполнения поиска/замены gsub необходимо проверить возможные дополнительные совпадения, прежде чем он сможет определить, закончил ли он. sub выполняет только один и заканчивается. Рассмотрим gsub как минимум два вызова sub.

Также важно помнить, что gsub и sub также могут быть ограничены плохо написанным регулярным выражением, которое встречается гораздо медленнее, чем поиск подстроки. Если возможно, привяжите регулярное выражение, чтобы получить максимальную скорость от него. Здесь есть ответы на "Переполнение стека", демонстрирующие, что для поиска требуется поиск, если вам нужна дополнительная информация.

Ответ 2

Как и в ответ Пабло выше, но очиститель оттенков:

str[1..-1]

Вернет массив от 1 до последнего символа.

'Hello World'[1..-1]
 => "ello World"

Ответ 3

Мы можем использовать срез для этого:

val = "abc"
 => "abc" 
val.slice!(0)
 => "a" 
val
 => "bc" 

Используя slice!, мы можем удалить любой символ, указав его индекс.

Ответ 4

Я предпочитаю это:

str = "[12,23,987,43"
puts str[1..-1]
>> 12,23,987,43

Ответ 5

Если вы всегда хотите снять ведущие скобки:

"[12,23,987,43".gsub(/^\[/, "")

Если вы просто хотите удалить первый символ, и знаете, что он не будет в многобайтном наборе символов:

"[12,23,987,43"[1..-1]

или

"[12,23,987,43".slice(1..-1)

Ответ 6

Рубин 2. 5+

Начиная с Ruby 2.5 вы можете использовать delete_prefix или delete_prefix! добиться этого в читабельной форме.

В этом случае "[12,23,987,43".delete_prefix("[").

Больше информации здесь:

https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/

https://bugs.ruby-lang.org/issues/12694

'invisible'.delete_prefix('in') #=> "visible"
'pink'.delete_prefix('in') #=> "pink"

Обратите внимание, что вы также можете использовать это, чтобы удалить элементы из конца строки с помощью delete_suffix и delete_suffix!

'worked'.delete_suffix('ed') #=> "work"
'medical'.delete_suffix('ed') #=> "medical"

https://bugs.ruby-lang.org/issues/13665

Редактировать:

Используя настройку Tin Man, он тоже выглядит довольно быстро (под последними двумя записями delete_p и delete_p!). Не совсем уместен предыдущий фаворит по скорости, хотя очень читабелен.

2.5.0
              user     system      total        real
[0]       0.174766   0.000489   0.175255 (  0.180207)
[/^./]    0.318038   0.000510   0.318548 (  0.323679)
[/^\[/]   0.372645   0.001134   0.373779 (  0.379029)
sub+      0.460295   0.001510   0.461805 (  0.467279)
sub       0.498351   0.001534   0.499885 (  0.505729)
gsub      1.669837   0.005141   1.674978 (  1.682853)
[1..-1]   0.199840   0.000976   0.200816 (  0.205889)
slice     0.279661   0.000859   0.280520 (  0.285661)
length    0.268362   0.000310   0.268672 (  0.273829)
eat!      0.341715   0.000524   0.342239 (  0.347097)
reverse   0.335301   0.000588   0.335889 (  0.340965)
delete_p  0.222297   0.000832   0.223129 (  0.228455)
delete_p!  0.225798   0.000747   0.226545 (  0.231745)

Ответ 7

Неэффективная альтернатива:

str.reverse.chop.reverse

Ответ 8

Например: a = "One Two Three"

1.9.2-p290 > a = "One Two Three"
 => "One Two Three" 

1.9.2-p290 > a = a[1..-1]
 => "ne Two Three" 

1.9.2-p290 > a = a[1..-1]
 => "e Two Three" 

1.9.2-p290 > a = a[1..-1]
 => " Two Three" 

1.9.2-p290 > a = a[1..-1]
 => "Two Three" 

1.9.2-p290 > a = a[1..-1]
 => "wo Three" 

Таким образом вы можете удалить один за другим первый символ строки.

Ответ 9

Простой способ:

str = "[12,23,987,43"

removed = str[1..str.length]

Удивительный способ:

class String
  def reverse_chop()
    self[1..self.length]
  end
end

"[12,23,987,43".reverse_chop()

(Примечание: предпочитайте простой способ:))

Ответ 10

Благодаря @the-tin-man для составления тестов!

Увы, мне не очень нравится какое-либо из этих решений. Либо они требуют дополнительного шага для получения результата ([0] = '', .strip!), либо они не очень семантичны/понятны о том, что происходит ([1..-1]: "Um, диапазон от 1 до отрицательного 1? Yearg?" ), или они медленны или длинны для записи (.gsub, .length).

То, что мы пытаемся, является "сдвигом" (в языке Array), но возвращающим оставшиеся символы, а не тем, что было смещено. Позвольте использовать наш Ruby, чтобы сделать это возможным со строками! Мы можем использовать скоринговую операцию, но дать ей хорошее имя и взять аргумент, чтобы указать, сколько мы хотим отбросить фронт:

class String
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end
end

Но мы можем сделать это быстрее, но неудобно. В то время как мы находимся в этом, для полноты, напишем a #shift и #first для String (почему у Array есть все самое интересное?), Взяв arg, чтобы указать, сколько символов мы хотим удалить с самого начала:

class String
  def first(how_many = 1)
    self[0...how_many]
  end

  def shift(how_many = 1)
    shifted = first(how_many)
    self.replace self[how_many..-1]
    shifted
  end
  alias_method :shift!, :shift
end

Хорошо, теперь у нас есть хороший четкий способ вытаскивания символов с фронта строки, с помощью метода, который согласуется с Array#first и Array#shift (что действительно должно быть методом bang?). И мы можем легко получить модифицированную строку, а также с помощью #eat!. Hm, мы должны поделиться нашей новой мощностью eat! с Array? Почему бы и нет!

class Array
  def eat!(how_many = 1)
    self.replace self[how_many..-1]
  end
end

Теперь мы можем:

> str = "[12,23,987,43" #=> "[12,23,987,43"
> str.eat!              #=> "12,23,987,43"
> str                   #=> "12,23,987,43"

> str.eat!(3)           #=> "23,987,43"
> str                   #=> "23,987,43"

> str.first(2)          #=> "23"
> str                   #=> "23,987,43"

> str.shift!(3)         #=> "23,"
> str                   #=> "987,43"

> arr = [1,2,3,4,5]     #=> [1, 2, 3, 4, 5] 
> arr.eat!              #=> [2, 3, 4, 5] 
> arr                   #=> [2, 3, 4, 5] 

Это лучше!

Ответ 11

str = "[12,23,987,43"

str[0] = ""

Ответ 12

class String
  def bye_felicia()
    felicia = self.strip[0] #first char, not first space.
    self.sub(felicia, '')
  end
end

Ответ 13

Использование регулярного выражения:

str = 'string'
n = 1  #to remove first n characters

str[/.{#{str.size-n}}\z/] #=> "tring"

Ответ 14

Я считаю хорошим решением быть str.delete(str[0]) для его читабельности, хотя я не могу подтвердить его производительность.

Ответ 15

list = [1,2,3,4] list.drop(1)

# => [2,3,4]

List удаляет один или несколько элементов с начала массива, не изменяет массив и возвращает сам массив вместо удаленного элемента.