Supprimer la sous-chaîne de la chaîne


193

Je me demande simplement s'il existe une méthode pour supprimer une chaîne d'une autre chaîne? Quelque chose comme ça:

class String
  def remove(s)
    self[s.length, self.length - s.length]
  end
end

Réponses:


263

Vous pouvez utiliser la méthode slice:

a = "foobar"
a.slice! "foo"
=> "foo"
a
=> "bar"

il y a un non '!' version aussi. Plus d'informations peuvent également être consultées dans la documentation des autres versions: http://www.ruby-doc.org/core/classes/String.html#method-i-slice-21


1
Très élégant! Vous pouvez également utiliser []s pour la version non-bang.
Matheus Moreira

65
Cela a un mauvais effet secondaire de renvoyer le texte supprimé (ou le texte recherché). Malheureusement pour l'enchaînement sur le résultat de la suppression.
Mike

10
Comment renvoyez-vous la chaîne tranchée sans affecter l'original? Par exemple, si j'ai "bonjour le monde", je veux couper "bonjour" et retourner juste la partie "monde", sans modifier l'objet chaîne d'origine?
jhabbott

14
@Mike"foobar".tap{|s| s.slice!("foo")}.upcase
Ernest

7
@bcackerman - deletene fonctionnerait pas, car il supprime tous les personnages que vous passez:'hello world'.delete('hello') #=> ' wrd'
rouillé

165

Que diriez-vous de str.gsub("subString", "") consulter le Doc Ruby


38
subserait plus approprié que gsub, puisque l'OP ne souhaite supprimer la sous-chaîne qu'au début de la chaîne, pas tout au long de la chaîne (regardez son exemple de code). Et l'utilisation d'une expression régulière, comme celle-ci, serait mieux: str.sub(/^subString/, '')- car elle garantit que la sous-chaîne ne sera définitivement supprimée que depuis le début.
Alex D

@AlexD Utiliser un regex serait mieux, mais c'est dangereux si nous ne pouvons pas être sûrs qu'il subStringn'inclut aucun caractère spécial regex.
David Moles

@DavidMoles, dans ce cas, /^subString/est un littéral, nous pouvons donc être sûrs qu'il ne contient aucun métacaractère. Si vous substituez une autre chaîne en une expression régulière, vous pouvez le faire: /#{Regexp.escape(str)}/.
Alex D

Dans la réponse, oui, mais pas dans la question du PO. Merci pour le pointeur vers Regexp.escape(), cependant.
David Moles

106

S'il s'agit de la fin de la chaîne, vous pouvez également utiliser chomp:

"hello".chomp("llo")     #=> "he"

si l'expression était a.chomp ("llo"), chomp! est plus précis.
Fernando Gonzalez Sanchez

1
C'est plus propre que slice !, car cela n'a aucun effet secondaire.
Ardee Aram

5
Si c'est depuis le début de la chaîne, vous pouvez également l'utiliser chompen combinaison avec reverse:"hello".reverse.chomp("he".reverse).reverse #=> "llo"
amoebe

45

Si vous n'avez qu'une seule occurrence de la chaîne cible, vous pouvez utiliser:

str[target] = ''

ou

str.sub(target, '')

Si vous avez plusieurs occurrences d'utilisation cible:

str.gsub(target, '')

Par exemple:

asdf = 'foo bar'
asdf['bar'] = ''
asdf #=> "foo "

asdf = 'foo bar'
asdf.sub('bar', '') #=> "foo "
asdf = asdf + asdf #=> "foo barfoo bar"
asdf.gsub('bar', '') #=> "foo foo "

Si vous devez effectuer des substitutions sur place, utilisez les "!"versions de gsub!et sub!.


2
rubis est amusant! aime vraiment voir des trucs comme:asdf['bar'] = ''
Peter Butkovic

1
Je n'appellerais pas cela "amusant" - non intuitif, peut-être.
Jmoney38

31

Si vous utilisez Rails, il y en a aussi remove.

Par exemple, les "Testmessage".remove("message")rendements "Test".

Attention: cette méthode supprime toutes les occurrences


1
Ce n'est pas une réponse Ruby vanille, mais la réponse acceptée n'est pas tout à fait ce que la plupart des gens recherchent. Malheureusement, la sliceméthode ne renvoie pas la partie de la chaîne qui est tranchée, elle renvoie le "couteau"
Dylan Pierce

1
@DylanPierce, il est assez facile d'implémenter une fonction qui fait cela en utilisantslice! def gimme_the_slice(my_string, my_slice) my_string.slice!(my_slice) my_string
Bennett Talpers

1
Ah c'est vrai, bang-ifying est la façon dont Ruby modifie la variable existante. Merci @BennettTalpers
Dylan Pierce

26

Ruby 2.5+

Si votre sous-chaîne se trouve au début ou à la fin d'une chaîne, alors Ruby 2.5 a introduit les méthodes pour cela:

  • delete_prefix pour supprimer une sous-chaîne du début de la chaîne
  • delete_suffix pour supprimer une sous-chaîne de la fin de la chaîne


1

Si j'interprète correctement, cette question semble demander quelque chose comme une opération moins (-) entre les chaînes, c'est-à-dire l'opposé de l'opération plus (+) intégrée (concaténation).

Contrairement aux réponses précédentes, j'essaie de définir une telle opération qui doit obéir à la propriété:

SI c = a + b ALORS c - a = b ET c - b = a

Pour ce faire, nous n'avons besoin que de trois méthodes Ruby intégrées:

'abracadabra'.partition('abra').values_at(0,2).join == 'cadabra'.

Je ne vais pas expliquer comment cela fonctionne, car il peut être facilement compris en exécutant une méthode à la fois.

Voici un code de preuve de concept:

# minus_string.rb
class String
  def -(str)
    partition(str).values_at(0,2).join
  end
end

# Add the following code and issue 'ruby minus_string.rb' in the console to test
require 'minitest/autorun'

class MinusString_Test < MiniTest::Test

  A,B,C='abra','cadabra','abracadabra'

  def test_C_eq_A_plus_B
    assert C == A + B
  end

  def test_C_minus_A_eq_B
    assert C - A == B
  end

  def test_C_minus_B_eq_A
    assert C - B == A
  end

end

Un dernier conseil si vous utilisez une version récente de Ruby (> = 2.0): utilisez des raffinements au lieu de singe-patching String comme dans l'exemple précédent.

C'est aussi simple que:

module MinusString
  refine String do
    def -(str)
      partition(str).values_at(0,2).join
    end
  end
end

et ajoutez using MinusStringavant les blocs où vous en avez besoin.


+1 pour les concepts de raffinements. Bien que la classe String de patch de singe soit probablement une surpuissance pour ce cas d'utilisation, nous devons parfois faire des patchs de singe et le concept de raffinements brille vraiment.
wondersz1

-2

voici ce que je ferais

2.2.1 :015 > class String; def remove!(start_index, end_index) (end_index - start_index + 1).times{ self.slice! start_index }; self end; end;
2.2.1 :016 >   "idliketodeleteHEREallthewaytoHEREplease".remove! 14, 32
 => "idliketodeleteplease" 
2.2.1 :017 > ":)".remove! 1,1
 => ":" 
2.2.1 :018 > "ohnoe!".remove! 2,4
 => "oh!" 

Formaté sur plusieurs lignes:

class String
    def remove!(start_index, end_index)
        (end_index - start_index + 1).times{ self.slice! start_index }
        self
    end 
end

-7
def replaceslug
  slug = "" + name
    @replacements = [
      [ "," , ""],
      [ "\\?" , ""],
      [ " " , "-"],
      [ "'" , "-"],
      [ "Ç" , "c"],
      [ "Ş" , "s"],
      [ "İ" , "i"],
      [ "I" , "i"],
      [ "Ü" , "u"],
      [ "Ö" , "o"],
      [ "Ğ" , "g"],
      [ "ç" , "c"],
      [ "ş" , "s"],
      [ "ı" , "i"],
      [ "ü" , "u"],
      [ "ö" , "o"],
      [ "ğ" , "g"],
    ]
  @replacements.each do |pair|
    slug.gsub!(pair[0], pair[1])
  end
  self.slug = slug.downcase
end

1
Pourquoi tant de votes négatifs? qu'avez-vous fait de mal .. trop large peut
zee

L'OP n'a pas demandé de retirer Öpar exemple.
Iulian Onofrei
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.