web-dev-qa-db-de.com

Was ist der einfachste Weg, um das erste Zeichen aus einer Zeichenkette zu entfernen?

Beispiel:

[12,23,987,43

Was ist der schnellste und effizienteste Weg, um "[" Zu entfernen, indem Sie vielleicht ein chop() verwenden, aber für das erste Zeichen?

165
NullVoxPopuli

Ich bevorzuge mit etwas wie:

 asdf = "[12,23,987,43" 
 asdf [0] = '' 
 
 p asdf 
 # >> "12, 23.987,43 "

Ich bin immer auf der Suche nach der schnellsten und lesbarsten Methode:

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

Laufen auf meinem 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)

Aktualisierung, um eine weitere vorgeschlagene Antwort aufzunehmen:

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

Was in ... endet:

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)

Und eine andere mit /^./ um das erste Zeichen zu finden:

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

Was in ... endet:

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

Hier ist ein weiteres Update für schnellere Hardware und eine neuere Version von 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)

Warum ist gsub so langsam?

Nach dem Suchen/Ersetzen muss gsub nach möglichen zusätzlichen Übereinstimmungen suchen, bevor festgestellt werden kann, ob die Suche abgeschlossen ist. sub macht nur einen und endet. Betrachten Sie gsub als wären es mindestens zwei sub Aufrufe.

Beachten Sie auch, dass gsub und sub auch durch schlecht geschriebene reguläre Ausdrücke beeinträchtigt werden können, die viel langsamer als eine Teilstringsuche übereinstimmen. Wenn möglich, verankern Sie den Regex, um die maximale Geschwindigkeit zu erzielen. Hier auf Stack Overflow finden Sie Antworten, die zeigen, dass Sie nach weiteren Informationen suchen müssen.

218
the Tin Man

Ähnlich wie Pablos Antwort oben, aber ein Schattenreiniger:

str[1..-1]

Gibt das Array von 1 bis zum letzten Zeichen zurück.

'Hello World'[1..-1]
 => "Ello World"
279
Jason Stirk

Wir können slice verwenden, um dies zu tun:

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

Mit slice! Wir können jedes Zeichen löschen, indem wir seinen Index angeben.

48
balanv

Ich bevorzuge das:

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

Wenn Sie immer führende Klammern entfernen möchten:

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

Wenn Sie nur das erste Zeichen entfernen möchten und wissen, dass es nicht in einem Multibyte-Zeichensatz enthalten ist:

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

oder

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

Ruby 2.5+

Ab Ruby 2.5 können Sie delete_prefix Oder delete_prefix! Verwenden, um dies lesbar zu machen.

In diesem Fall "[12,23,987,43".delete_prefix("[").

Mehr Infos hier:

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"

N.B. Sie können dies auch verwenden, um Elemente mit delete_suffix und delete_suffix! vom Ende einer Zeichenfolge zu entfernen.

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

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

Bearbeiten:

Mit dem Benchmark-Setup des Tin Man sieht es auch ziemlich schnell aus (unter den letzten beiden Einträgen delete_p Und delete_p!). Pipe ganz die vorherigen Favoriten für die Geschwindigkeit, obwohl sehr gut lesbar ist.

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)
11
SRack

Ineffiziente Alternative:

str.reverse.chop.reverse
6
jaamun

Zum Beispiel: a = "Eins Zwei Drei"

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" 

Auf diese Weise können Sie ein einzelnes erstes Zeichen der Zeichenfolge entfernen.

4
Rubyist

Vielen Dank an @ the-tin-man für die Zusammenstellung der Benchmarks!

Leider mag ich keine dieser Lösungen wirklich. Entweder benötigen sie einen zusätzlichen Schritt, um das Ergebnis zu erhalten ([0] = '', .strip!), Oder sie wissen nicht genau, was passiert ([1..-1]: "Ähm, ein Bereich von 1 bis negativ 1? Yearg? "), oder sie sind langsam oder langwierig zu schreiben (.gsub, .length).

Was wir versuchen, ist eine „Verschiebung“ (in der Array-Sprache), die jedoch die verbleibenden Zeichen zurückgibt, anstatt die verschobenen Zeichen. Verwenden wir unser Ruby), um dies mit Strings zu ermöglichen! Wir können die schnelle Klammeroperation verwenden, aber einen guten Namen vergeben und ein Argument verwenden, um anzugeben, wie viel wir von der Vorderseite abschneiden möchten :

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

Mit dieser schnellen, aber unhandlichen Bracket-Operation können wir jedoch noch mehr tun. Schreiben wir der Vollständigkeit halber #shift Und #first Für String (warum sollte Array den ganzen Spaß haben?), Und geben Sie mit einem Argument an, wie viele Zeichen wir wollen vom anfang entfernen:

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

Ok, jetzt haben wir eine gute Möglichkeit, Zeichen von der Vorderseite eines Strings abzuziehen, mit einer Methode, die mit Array#first Und Array#shift Konsistent ist (die eigentlich eine Knallmethode sein sollte ??) . Und wir können den modifizierten String auch mit #eat! Leicht bekommen. Hm, sollten wir unsere neue eat! - Kraft mit Array teilen? Warum nicht!

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

Jetzt können wir:

> 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] 

Das ist besser!

3
brookr

Einfacher Weg:

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

removed = str[1..str.length]

Genialer Weg:

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

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

(Hinweis: lieber einfach :))

3
Pablo Fernandez
str = "[12,23,987,43"

str[0] = ""
2
Handcraftsman

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

# => [2,3,4]

List löscht ein oder mehrere Elemente am Anfang des Arrays, verändert das Array nicht und gibt das Array selbst anstelle des gelöschten Elements zurück.

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

Regex verwenden:

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

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

Ich finde, dass eine gute Lösung wegen ihrer Lesbarkeit str.delete(str[0]) ist, obwohl ich nicht bezeugen kann, dass sie funktioniert.

0
zeitchef