Ruby、文字列から最後のN文字を削除しますか?


263

n文字列から最後の文字を削除する好ましい方法は何ですか?


サフィックスがわかっている場合(一番上の答えはこれを探すためにここにたくさん来ることを示唆しています)、delete_suffixRuby 2.5から使用できます。詳細はこちら
SRack

回答:


36

Ruby 2.5以降

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

メソッドに関するドキュメントはこちらです。

あなたがサフィックスが何であるか知っているなら、これは慣用的です(そして私はここで他の答えよりもさらに読みやすいと思います):

'abc123'.delete_suffix('123')     # => "abc"
'abc123'.delete_suffix!('123')    # => "abc"

これは、トップの回答よりもはるかに高速です(bangメソッドでは約40%)。同じベンチマークの結果は次のとおりです。

                     user     system      total        real
chomp            0.949823   0.001025   0.950848 (  0.951941)
range            1.874237   0.001472   1.875709 (  1.876820)
delete_suffix    0.721699   0.000945   0.722644 (  0.723410)
delete_suffix!   0.650042   0.000714   0.650756 (  0.651332)

これが役立つことを願っています。現在、このメソッドは正規表現を受け入れないため、サフィックスがわからない場合、当面は有効ではありません。しかし、受け入れられた回答(更新:執筆時点)が同じことを指示しているので、これは一部の人々にとって役立つかもしれないと思いました。


1
@JPSilvashy私はチェックマークを失うことをこれまで以上に満足していません。これは素晴らしい答えです。
ウェインコンラッド

1
これは素晴らしくて速い機能ですが、これは正解ではありませんWhat is the preferred way of removing the last n characters from a string?
Sam

1
@Samのフィードバックに感謝します。この質問はほぼ9年間回答があり、執筆時点では261の賛成票で、この質問と同じように機能しました。JPはそれを受け入れ、最近これに切り替えたので、彼らの質問に答えたと思います:)私はこれを現代的な選択肢としてポップし、ここに着陸する人々を助けることを願っています。実際、私はこのすべてを質問でカバーしました-私はこの方法がすぐに正規表現を受け入れることを望んでいますが、これの真下にあなたのケースのための完璧な代替があります
SRack

316
irb> 'now is the time'[0...-4]
=> "now is the "

9
これはRuby 1.9でのみ機能することに注意してください。Ruby 1.8では、これにより、最後の文字ではなく、最後のバイトが削除されます
イェルクWミッターク

2
しかし、1.8.xを使用している場合は、おそらく「バイト」を意味していました。
DigitalRoss、2011

4
これは機能しますが、 'abc123'.chomp(' 123 ')は、短い文字列と非常に長い文字列の両方で2倍高速であることがわかります。(Ruby 2.0.0-p247)誰かがこれを確認できますか?
2013年

10
なぜこの特定の例が機能しないのか不思議に思う人のために.. 2ではなく3つのドットがある[0...-4][0..-4]
rorofromfrance

2
@Plamarob私は、chompが53ナノ秒速いと言うのは、2倍速いと言うよりも適切だと思います。次に、それを使用することのコストと価値をより適切に見積もることができ、それが特定の状況で最適化すべきものであるかどうかを判断できます。
セソイド2016年

266

削除する文字が常に同じ文字である場合は、次のことを考慮してchompください。

'abc123'.chomp('123')    # => "abc"

の利点は次のchompとおりです。カウントせず、コードはそれが何をしているかをより明確に伝えます。

引数なしでchomp、DOSまたはUnixの行末を削除します(存在する場合)。

"abc\n".chomp      # => "abc"
"abc\r\n".chomp    # => "abc"

コメントから、使用速度と#chomp範囲使用の速度の問題がありました。2つを比較するベンチマークは次のとおりです。

require 'benchmark'

S = 'asdfghjkl'
SL = S.length
T = 10_000
A = 1_000.times.map { |n| "#{n}#{S}" }

GC.disable

Benchmark.bmbm do |x|
  x.report('chomp') { T.times { A.each { |s| s.chomp(S) } } }
  x.report('range') { T.times { A.each { |s| s[0...-SL] } } }
end

ベンチマーク結果(CRuby 2.13p242を使用):

Rehearsal -----------------------------------------
chomp   1.540000   0.040000   1.580000 (  1.587908)
range   1.810000   0.200000   2.010000 (  2.011846)
-------------------------------- total: 3.590000sec

            user     system      total        real
chomp   1.550000   0.070000   1.620000 (  1.610362)
range   1.970000   0.170000   2.140000 (  2.146682)

したがって、chompは範囲を使用するよりも22%高速です。


5
チョップもオプションです。何が削除されるかについての煩わしさが軽減されます。
Andrew Grimm

1
私は反対が実際に本当であることがわかりました。実際には、.chompは常に2倍の速度で動作しているように見えます。
プラズマロブ2013年

3
@ Plamarob、Rubyのベンチマークはしばしば驚くべきものです。私はよく間違っているので、何が速くなるかを推測することはもうありません。また、ベンチマーク結果により改善される場合は、お気軽に編集してください。
ウェインコンラッド

1
コードを正しく読んでいる場合、範囲はchompよりも約53ナノ秒長くかかります。これは特定の状況では大きな抵抗になる可能性がありますが、(相対だけでなく)絶対速度を念頭に置くと、コードベースを調べてすべての範囲を適切なものに変更する必要があるかどうかがわかります(該当する場合)。おそらく違います。
セソイド

1
よく働く。そして、あなたchomp!()は文字列をその場で操作するために使用できます。
Joshua Pinter

57
str = str[0...-n]

5
これはRuby 1.9でのみ機能することに注意してください。Ruby 1.8では、これにより、最後の文字ではなく、最後のバイトが削除されます
イェルクWミッターク

5
-nは文字列の末尾からn文字を取り出すため、3つのドット(...)は覚えやすいので、これは選択した回答よりも優れています。
lulalala

また、「abcd」[0 ..- 2]#=>「abc」、「abcd」[0 ...- 2]#=>「ab」。私の意見では、3つのドット範囲オプションを使用すると、よりわかりやすいコードになります。
mokagio 2013

31

お勧めしchopます。私はそれがコメントの1つで言及されたと思いますが、リンクや説明はありませんので、これが私がより良いと思う理由です:

文字列から最後の文字を削除するだけで、そのために値を指定する必要はありません。

複数のキャラクターを削除する必要がある場合chompは、最善の策です。これはrubyのドキュメントについてのコメントchopです:

最後の文字が削除された新しい文字列を返します。文字列が\ r \ nで終わる場合、両方の文字が削除されます。空の文字列にチョップを適用すると、空の文字列が返されます。String#chompは、レコード区切り文字で終わらない場合は文字列を変更しないため、多くの場合、より安全な代替手段です。

これは主に\r\n、たとえばs、単語を単数形にするために、単純な文字列から最後の文字を削除するために使用したような区切り記号を削除するために使用されます。


1
最後の1文字だけを削除しませんか?質問は複数形の「文字」についてです
maetthew

1
はい、そうですが、chomp( 'chars')は最後の 'chars'を削除します。OPが特定の文字を必要とするのか、N文字だけを必要とするのかは、私にはわかりませんでした。
角兵衛2013

ええ、これが答えです。1文字だけ削除したい場合のみです(私もそうでした)。
Quv 2016年

29
name = "my text"
x.times do name.chop! end

ここでコンソール:

>name = "Nabucodonosor"
 => "Nabucodonosor" 
> 7.times do name.chop! end
 => 7 
> name
 => "Nabuco" 

これは効率的ですか?他の回答とのベンチマーク比較の価値があるようです:)
SRack

16

最後のn文字を削除することは、最初のlength - n文字を保持することと同じです。

アクティブなサポートが含まString#firstString#last便利な方法を提供する方法は、維持するか、最初/最後のドロップするn文字を:

require 'active_support/core_ext/string/access'

"foobarbaz".first(3)  # => "foo"
"foobarbaz".first(-3) # => "foobar"
"foobarbaz".last(3)   # => "baz"
"foobarbaz".last(-3)  # => "barbaz"

7

レールを使用している場合は、以下を試してください。

"my_string".last(2) # => "ng"

[編集済み]

最後の2文字なしで文字列を取得するには:

n = "my_string".size
"my_string"[0..n-3] # => "my_stri"

注:最後の文字列charはn-1にあります。したがって、最後の2つを削除するには、n-3を使用します。


2
これは最後の2文字を削除しません。それらを返します。
JP Silvashy 2015

1
最初に文字列を測定する必要はありません。rubyは文字列の末尾から負のインデックスをネイティブに使用します
Devon Parsons

3

あなたはいつものようなものを使うことができます

 "string".sub!(/.{X}$/,'')

X削除する文字数はどこですか。

または結果の割り当て/使用:

myvar = "string"[0..-X]

ここXで、削除する文字数に1加えた数です。



1

クラスメソッドの作成に問題がなく、切り取った文字が必要な場合は、次のことを試してください。

class String
  def chop_multiple(amount)
    amount.times.inject([self, '']){ |(s, r)| [s.chop, r.prepend(s[-1])] }
  end
end

hello, world = "hello world".chop_multiple 5
hello #=> 'hello '
world #=> 'world'


0

削除したい文字が常に同じ文字である場合は、chompを検討してください。

「abc123」。チョンプ( '123')


-3
x = "my_test"
last_char = x.split('').last

3
質問は、文字列から最後のN文字を削除することであり、最後の文字を見つけることではありませんでした
unnitallman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.