Usuń podciąg z łańcucha

193

Zastanawiam się tylko, czy istnieje metoda usunięcia ciągu z innego ciągu? Coś takiego:

class String
  def remove(s)
    self[s.length, self.length - s.length]
  end
end
demas
źródło

Odpowiedzi:

263

Możesz użyć metody wycinania:

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

istnieje non „!” również wersja. Więcej informacji można również znaleźć w dokumentacji innych wersji: http://www.ruby-doc.org/core/classes/String.html#method-i-slice-21

Pete
źródło
1
Bardzo elegancko! Możesz także użyć []s dla wersji innej niż Bang.
Matheus Moreira,
65
Ma to zły efekt uboczny polegający na zwróceniu usuniętego tekstu (lub szukanego tekstu). Niefortunne dla powiązania wyniku usunięcia.
Mike
10
Jak zwrócić pocięty łańcuch i nie wpływać na oryginał? Na przykład, jeśli mam „hello world”, chcę pokroić „hello” i zwrócić tylko część „world” bez modyfikowania oryginalnego obiektu string?
jhabbott
14
@Mike"foobar".tap{|s| s.slice!("foo")}.upcase
Ernest,
7
@ backackerman - deletenie działa, ponieważ usuwa wszystkie znaki, które przekazujesz:'hello world'.delete('hello') #=> ' wrd'
zardzewiały
165

Co powiesz na str.gsub("subString", "") sprawdzenie Ruby Doc

Piyush Mattoo
źródło
38
subbyłoby bardziej odpowiednie niż gsub, ponieważ OP chce tylko usunąć podłańcuch z początku łańcucha, nie przez cały łańcuch (spójrz na jego przykładowy kod). A użycie wyrażenia regularnego, takiego jak ten, byłoby lepsze: str.sub(/^subString/, '')- ponieważ zapewnia, że ​​podciąg będzie zdecydowanie usuwany od samego początku.
Alex D
@AlexD Lepsze byłoby użycie wyrażenia regularnego, ale jest to niebezpieczne, jeśli nie możemy mieć pewności, subStringże nie zawiera żadnych znaków specjalnych wyrażenia regularnego.
David Moles,
@DavidMoles w tym przypadku /^subString/jest dosłowny, więc możemy być pewni, że nie zawiera żadnych metaznaków. Jeśli podstawiając inny ciąg znaków w regex, można to zrobić: /#{Regexp.escape(str)}/.
Alex D
W odpowiedzi tak, ale nie w pytaniu PO. Dzięki za wskaźnik do Regexp.escape().
David Moles
106

Jeśli jest to koniec ciągu, możesz także użyć chomp:

"hello".chomp("llo")     #=> "he"
Czekam na Dev ...
źródło
jeśli wyrażenie to a.chomp („llo”), chomp! jest bardziej precyzyjny.
Fernando Gonzalez Sanchez,
1
Jest to czystsze niż plasterek !, ponieważ nie ma żadnych skutków ubocznych.
Ardee Aram
5
Jeśli jest od początku ciągu, możesz także użyć chompw połączeniu z reverse:"hello".reverse.chomp("he".reverse).reverse #=> "llo"
amoebe
45

Jeśli masz tylko jedno wystąpienie ciągu docelowego, możesz użyć:

str[target] = ''

lub

str.sub(target, '')

Jeśli masz wiele wystąpień celu docelowego:

str.gsub(target, '')

Na przykład:

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 "

Jeśli chcesz dokonać zamiany w miejscu, użyj "!"wersji gsub!i sub!.

Blaszany Człowiek
źródło
2
ruby jest fajny! naprawdę lubię oglądać rzeczy takie jak:asdf['bar'] = ''
Peter Butkovic
1
Nie nazwałbym tego „zabawnym” - być może nieintuicyjnym.
Jmoney38
31

Jeśli używasz Railsów, jest tam również remove.

Np . "Testmessage".remove("message")Plony "Test".

Ostrzeżenie: ta metoda usuwa wszystkie wystąpienia

edwardmp
źródło
1
To nie jest waniliowa odpowiedź Ruby, ale zaakceptowana odpowiedź nie jest tym, czego większość ludzi szuka. Niestety slicemetoda nie zwraca części ciętego sznurka, ale zwraca „nóż”
Dylan Pierce
1
@DylanPierce jest dość łatwo zaimplementować funkcję, która robi to za pomocąslice! def gimme_the_slice(my_string, my_slice) my_string.slice!(my_slice) my_string
Bennett Talpers
1
Ach, właśnie tak, Bang-ifying jest jak Ruby modyfikuje istniejącą zmienną. Dzięki @BennettTalpers
Dylan Pierce
26

Ruby 2.5+

Jeśli twój podciąg znajduje się na początku łańcucha, to Ruby 2.5 wprowadził następujące metody:

Igor Drozdow
źródło
1

Jeśli dobrze interpretuję, to pytanie wydaje się wymagać czegoś takiego jak operacja minus (-) między łańcuchami, tj. Przeciwieństwo wbudowanej operacji plus (+) (konkatenacja).

W przeciwieństwie do poprzednich odpowiedzi próbuję zdefiniować taką operację, która musi być zgodna z właściwością:

JEŚLI c = a + b NASTĘPNIE c - a = b ORAZ c - b = a

Potrzebujemy tylko trzech wbudowanych metod Ruby, aby to osiągnąć:

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

Nie wyjaśnię, jak to działa, ponieważ można to łatwo zrozumieć, uruchamiając jedną metodę na raz.

Oto kod dowodu koncepcji:

# 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

Ostatnie słowo porady, jeśli używasz najnowszej wersji Rubiego (> = 2.0): użyj Uściśleń zamiast ciągów małpich łatek, jak w poprzednim przykładzie.

Jest to tak proste jak:

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

i dodaj using MinusStringprzed blokami tam, gdzie jest to potrzebne.

Claudio Floreani
źródło
+1 za koncepcje udoskonaleń. Podczas gdy łatanie małp klasy String jest prawdopodobnie przesadą w tym przypadku użycia, czasami musimy załatać małpy i koncepcja ulepszeń naprawdę na nich świeci.
wondersz1
-2

oto co bym zrobił

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!" 

Sformatowany w wielu wierszach:

class String
    def remove!(start_index, end_index)
        (end_index - start_index + 1).times{ self.slice! start_index }
        self
    end 
end
JayTarka
źródło
-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
ilkay
źródło
1
Po co tyle głosów? co zrobiłeś źle ... może zbyt szeroki
zee
OP nie poprosił Öna przykład o usunięcie .
Iulian Onofrei