web-dev-qa-db-fra.com

Quel est le moyen le plus simple de supprimer le premier caractère d'une chaîne?

Exemple:

[12,23,987,43

Quel est le moyen le plus rapide et le plus efficace de supprimer le "[", en utilisant peut-être un chop() mais pour le premier caractère?

165
NullVoxPopuli

Je préfère utiliser quelque chose comme:

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

Je cherche toujours le moyen le plus rapide et le plus lisible de faire les choses:

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

Courir sur mon 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)

Mise à jour pour intégrer une autre réponse suggérée:

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

Ce qui résulte en:

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)

Et un autre en utilisant /^./ pour trouver le premier caractère:

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

Ce qui résulte en:

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

Voici une autre mise à jour sur un matériel plus rapide et une version plus récente de 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)

Pourquoi Gsub est-il si lent?

Après avoir effectué une recherche/remplacement, gsub doit rechercher d'éventuelles correspondances supplémentaires avant de pouvoir déterminer si elle est terminée. sub ne fait qu'un et termine. Considérez gsub comme si c'était un minimum de deux appels sub.

De plus, il est important de se rappeler que gsub et sub peuvent également être handicapés par des expressions rationnelles mal écrites qui correspondent beaucoup plus lentement qu'une recherche de sous-chaîne. Si possible, ancrez l'expression rationnelle pour en tirer le maximum de vitesse. Il y a des réponses ici sur Stack Overflow qui démontrent qu'il est donc préférable de chercher si vous voulez plus d'informations.

218
the Tin Man

Semblable à la réponse de Pablo ci-dessus, mais un nettoyant d'ombre:

str[1..-1]

Renverra le tableau de 1 au dernier caractère.

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

Nous pouvons utiliser slice pour faire ceci:

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

En utilisant slice! nous pouvons supprimer n'importe quel caractère en spécifiant son index.

48
balanv

Je préfère ça:

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

Si vous voulez toujours supprimer les crochets principaux:

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

Si vous souhaitez simplement supprimer le premier caractère et que vous savez qu'il ne fera pas partie d'un jeu de caractères multi-octets:

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

ou

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

Rubis 2.5+

À partir de Ruby 2.5, vous pouvez utiliser delete_prefix ou delete_prefix! pour y parvenir de manière lisible.

Dans ce cas, "[12,23,987,43".delete_prefix("[").

Plus d'infos ici:

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. vous pouvez également l'utiliser pour supprimer des éléments de la fin d'une chaîne avec delete_suffix et delete_suffix!

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

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

Modifier:

En utilisant la configuration de référence de Tin Man, cela semble assez rapide aussi (sous les deux dernières entrées delete_p et delete_p!). Ne ( pas tout à fait ajoute les faves précédentes à la vitesse, bien que ce soit très lisible.

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

Alternative inefficace:

str.reverse.chop.reverse
6
jaamun

Par exemple: a = "Un Deux Trois"

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" 

De cette façon, vous pouvez supprimer un à un le premier caractère de la chaîne.

4
Rubyist

Merci à @ the-tin-man pour avoir établi les critères!

Hélas, je n'aime pas vraiment l'une de ces solutions. Soit ils nécessitent une étape supplémentaire pour obtenir le résultat ([0] = '', .strip!) ou ils ne sont pas très sémantiques/clairs sur ce qui se passe ([1..-1]: "Euh, une plage allant de 1 à négatif 1? Yearg? "), ou ils sont lents ou longs à écrire (.gsub, .length).

Ce que nous essayons de faire est un "décalage" (dans le langage Array), mais nous renvoyons les caractères restants plutôt que ce qui a été déplacé. Utilisons notre Ruby pour rendre cela possible avec des chaînes! Nous pouvons utiliser l'opération rapide crochet, mais lui donner un bon nom et prendre un argument pour spécifier combien nous voulons chompez à l'avant:

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

Mais nous pouvons faire plus avec cette opération de support rapide mais difficile à manier. Pendant que nous y sommes, pour être complets, écrivons un #shift et #first pour String (pourquoi Array devrait-il avoir tout le fun‽‽), en prenant un argument pour spécifier le nombre de caractères que nous voulons supprimer le début:

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, nous avons maintenant un moyen clair de tirer les caractères du début d'une chaîne, avec une méthode compatible avec Array#first et Array#shift (qui devrait être vraiment une méthode bang ??). Et nous pouvons aussi facilement obtenir la chaîne modifiée avec #eat!. Hm, devrions-nous partager notre nouveau pouvoir eat!ing avec Array? Pourquoi pas!

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

Maintenant nous pouvons:

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

C'est mieux!

3
brookr

Moyen facile:

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

removed = str[1..str.length]

Manière impressionnante:

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

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

(Remarque: préférez la solution de facilité :))

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

str[0] = ""
2
Handcraftsman

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

# => [2,3,4]

La liste supprime un ou plusieurs éléments au début du tableau, ne modifie pas le tableau et renvoie le tableau lui-même à la place de l'élément déposé.

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

Utiliser regex:

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

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

Je trouve une solution intéressante à être str.delete(str[0]) pour sa lisibilité, bien que je ne puisse pas attester de ses performances.

0
zeitchef