文字列から最初の文字を削除する最も簡単な方法は何ですか?


174

例:

[12,23,987,43

最初の文字に[aを使用して、「」を削除する最も速く効率的な方法は何chop()ですか?


1
回答を編集したので、選択した回答を変更できる可能性があります。Jason Stirkの回答が最も速く、非常に読みやすいので、あなたがそれを受賞できるかどうかを確認してください。
ティンマン

3
以下の回答によると、最速のstr [1 ..- 1]を使用してください。
Achyut Rastogi 2017

1
ルビー2.5の時点で、あなたは使用することができますdelete_prefixし、delete_prefix!- 以下の詳細を。ベンチマークする時間はありませんでしたが、すぐにやります!
SRack

更新:新しいメソッド(delete_prefix\ delete_prefix!)をベンチマークしましたが、かなり高速です。速度を上げるために以前のお気に入りを完全に無視するわけではありませんが、読みやすさはそれらが持つ素晴らしい新しいオプションであることを意味します!
SRack

回答:


233

私は次のようなものを使うのが好きです:

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)

もう1つ提案された回答を組み込むように更新しています:

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、それが終了したかどうかを判断する前に、可能な追加の一致をチェックする必要があります。sub1つだけ実行して終了します。gsub少なくとも2つのsub呼び出しであると考えてください。

また、それはそれを覚えておくことが重要だgsub、とsubも部分文字列の検索よりもはるかにゆっくりと一致下手に書かれた正規表現によってハンディキャップをすることができます。可能であれば、正規表現をアンカーして、そこから最大の速度を得る。Stack Overflowには、それを実証する回答があります。詳細については、検索してください。


34
これはRuby 1.9でのみ機能することに注意してください。Ruby 1.8では、これは最初の文字ではなく、文字列から最初のバイトを削除します。これはOPが必要とするものではありません。
イェルクWミッターク

+1:文字列の位置に1文字だけでなく、部分文字列を挿入することもできることをいつも忘れています。ありがとう!
ケツァルコアトル2013

"[12,23,987,43".delete "["
rupweb 2013

4
それはすべてのポジションからそれを削除します、それはOPが望んだものではありません:「...最初のキャラクターのために?」
Tin Man

2
what about "[12,23,987,43".shift ?」?"[12,23,987,43".shift NoMethodError: undefined method "[12,23,987,43":String`のシフト 'はどうですか?
ティンマン

293

上記のパブロの答えに似ていますが、日よけクリーナー:

str[1..-1]

1から最後の文字までの配列を返します。

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

13
+1回答に追加したベンチマーク結果を確認してください。あなたは最速のランタイムを持っています、それに私はそれはとてもきれいだと思います。
ティンマン

str[1,]上記と比較してのパフォーマンスはどうですか?
ボーア

1
@Bohr:str[1,]範囲はなので、2番目の文字を返します1:nilstr[1,999999]テール全体を取得するには、実際に計算された長さ、または長さよりも長くなることが保証されているもの(たとえば、int_maxを使用)を提供する必要があります。[1..-1]手動で長さを操作する必要がないので、(ベンチマークで[1..length]を参照)、より速く、おそらくクリーナーがあると
ケツァルコアトル

4
とても良い解決策です。ちなみに、最初と最後の文字を削除したい場合:str[1..-2]
pisaruk

50

これを行うには、sliceを使用できます。

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

を使用slice!すると、インデックスを指定して任意の文字を削除できます。


2
最初の文字を削除するためにslice!(0)使用asdf[0] = '' するのはばかげている(正規表現でgsubを使用して榴弾砲でフライを撃つような)ので、このエレガントなものが本当に選択された答えになるはずです。
f055 2016年

1
一見すると直感的には見えないかもしれ[]=ませんが、slice!追加の作業が必要な基礎となるCコードはそれほど必要ありません。合計します。議論は「どちらがより読みやすいですか?」かもしれません。私は[]=可読性を使用しているのを見つけましたが、私はC-> Perlの背景から来ています。Java開発者はおそらくそれが読みにくいと思います。どちらも、タスクが簡単に理解でき、保守可能であり、CPUに過度の負荷がかからない限り、許容できる方法です。
ティンマン

OK。関数がRORで多くのCPU負荷をかけるかどうかをどのように測定できるか知っていますか?または、ミリ秒またはナノ秒単位の実行時間差を使用する必要がありますか?
balanv 2016年

18

Ruby 2.5以降

Ruby 2.5以降では、delete_prefixまたはdelete_prefix!を使用して、読み取り可能な方法でこれを実現できます。

この場合"[12,23,987,43".delete_prefix("[")

詳細はこちら:

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

注意:これを使用してdelete_suffix、およびで文字列の末尾からアイテムを削除することもできますdelete_suffix!

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

編集:

Tin Manのベンチマークセットアップを使用すると、非常に高速に見えます(最後の2つのエントリ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)


14

常に先行括弧を取り除きたい場合:

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

最初の文字を削除したいだけで、マルチバイト文字セットにならないことがわかっている場合:

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

または

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

1
"[12,23,987,43".sub(/^\[+/, "")代わりに使用しますgsub(/^\[/, "")。1つ目は、正規表現エンジンがすべての一致を検索できるようにし、1つのアクションで置き換えられ、Ruby 1.9.3と比べて速度が約2倍向上します。
ティンマン

1
文字列を扱っているので、これはgsub(/\A\[/, "") どうでしょうか?
Sagar Pandya 2017年


4

例: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" 

このようにして、文字列の最初の文字を1つずつ削除できます。


3
これは、Jason Stirkの回答と同じですが、彼が数か月前に提出したものだけです。
Tin Man

3

簡単な方法:

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()

(注:簡単な方法をお勧めします:))


1
「チョップ」のセマンティクスを保持したい場合は、次のようにすることができます"[12,23,987,43".reverse.chop.reverse
Chris Heald

これは、1つの文字を削除するだけのかなり大きなパフォーマンスオーバーヘッドです
Pablo Fernandez

7
[1..self.length]ではなく[1 ..- 1]を使用しないのはなぜですか?
horseyguy

サルのパッチ適用の例は、この質問にはかなり外れています。それは単に無関係で醜いIMOです。
dredozubov 2014年

3

ベンチマークをまとめてくれた@ the-tin-manに感謝します。

悲しいかな、私はそれらの解決策のどれも本当に好きではありません。結果を取得するために追加の手順が必要か([0] = ''.strip!)、または何が起こっているかについて意味論的/明確ではない([1..-1]: "ええと、1から負の1までの範囲?Yearg?")、または遅いまたは長い書き出す(.gsub.length)。

私たちが試みているのは「シフト」(配列の用語)ですが、シフトされたものではなく、残りの文字を返します。Rubyを使って文字列でこれを可能にしましょう!スピーディなブラケット操作を使用できますが、適切な名前を付け、引数を使用して、前面を切り詰める量を指定します。

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

しかし、その迅速でありながら扱いにくいブラケット操作でできることは他にもあります。その間、完全を期すために、#shift#firstを書いてみましょう(なぜ配列にはすべての楽しみがあるべきですか?)引数を取り、最初から削除する文字数を指定します。

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#firstandと一貫したメソッドを使用して、文字列の先頭から文字Array#shiftを削除する明確な方法があります(これは本当にbangメソッドでなければなりませんか?)。そして、変更された文字列もで簡単に取得できます#eat!。ええと、私たちは新しいeat!ingパワーをアレイと共有すべきですか?何故なの!

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] 

いいね!


2
chip()代わりにchop()(およびchimp()のアナログとしてchomp())という名前のそのような関数について、Perlフォーラムで何年も前に議論したことを覚えています。
Mark Thomas

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

str[0] = ""

7
これはRuby 1.9でのみ機能することに注意してください。Ruby 1.8では、これは最初の文字ではなく、文字列から最初のバイトを削除します。これはOPが必要とするものではありません。
イェルクWミッターク



0

str.delete(str[0])読みやすさのために良い解決策を見つけましたが、そのパフォーマンスは証明できません。


0

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

# => [2,3,4]

Listは、配列の先頭から1つ以上の要素を削除し、配列を変更せず、削除された要素の代わりに配列自体を返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.