从字符串中删除子字符串。

232
我想知道是否有一种方法可以从另一个字符串中删除字符串?就像这样:
class String
  def remove(s)
    self[s.length, self.length - s.length]
  end
end
9个回答

287

1
非常优雅!您还可以使用[]来表示非感叹号版本。 - Matheus Moreira
73
这会导致一个负面的副作用,即返回已删除的文本(或所搜索的文本),这对于在删除结果上链接操作来说是不幸的。 - Mike
10
如何返回切片后的字符串而不影响原始字符串对象?例如,如果我有字符串"hello world",我想切片出"hello "并返回只有"world"部分的字符串,而不修改原始字符串对象。 - jhabbott
14
@Mike "foobar".tap{|s| s.slice!("foo")}.upcase - Ernest
8
由于delete会删除你传递进去的所有字符,因此无法使用它来删除特定的单词。例如: 'hello world'.delete('hello') #=> ' wrd' - rusty
显示剩余6条评论

189

如何使用 str.gsub("subString", "")? 请查看 Ruby Doc


47
根据原文意思,建议使用sub而不是gsub来删除字符串中的子串,因为原作者只想从字符串开头删除子串,而不是整个字符串(请看他的示例代码)。使用正则表达式会更好,例如:str.sub(/^subString/, '') -- 因为它确保子串只会从字符串开头被删除。 - Alex D
@AlexD 使用正则表达式会更好,但如果我们不能确定subString不包含任何正则表达式特殊字符,则会有风险。 - David Moles
@DavidMoles,在这种情况下,/^subString/是一个字面量,因此我们可以非常确定它不包含任何元字符。如果您要将其他字符串替换为正则表达式,则可以使用以下方法:/#{Regexp.escape(str)}/ - Alex D
在回答中是的,但不在OP的问题中。不过感谢指向Regexp.escape()的提示。 - David Moles

130
如果字符串结尾处需要操作,您也可以使用 chomp
"hello".chomp("llo")     #=> "he"

如果表达式是 a.chomp("llo"),那么 chomp! 更加精确。 - Fernando Gonzalez Sanchez
2
这比切片更干净!因为它没有副作用。 - Ardee Aram
6
如果是从字符串开头开始,你也可以将 chompreverse 结合使用:"hello".reverse.chomp("he".reverse).reverse #=> "llo"。该代码的作用是从字符串开头删除以指定子串结尾的部分,并返回剩余的字符串。 - amoebe

62

Ruby 2.5+

如果你的子字符串在字符串的开头或结尾,那么Ruby 2.5+版本引入了如下方法:

  • delete_prefix:用于从字符串开头删除一个子字符串
  • delete_suffix:用于从字符串末尾删除一个子字符串

57

如果目标字符串只出现一次,您可以使用:

str[target] = ''
或者
str.sub(target, '')

如果您有多个目标的出现,请使用:

str.gsub(target, '')

例如:

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 "

如果您需要进行原地替换,请使用 gsub!sub!"!" 版本。


3
红宝石很有趣!真的很喜欢看到这样的东西:asdf['bar'] = '' - Peter Butkovic
2
我不会称之为“有趣”——也许是非直观的。 - Jmoney38

42
如果您在使用Rails,还可以使用remove。例如,"Testmessage".remove("message")将返回"Test"。注意:此方法会删除所有出现的匹配项。

1
这不是一个普通的 Ruby 答案,但是被接受的答案并不完全符合大多数人的需求。不幸的是,slice 方法并不返回被切割的字符串部分,而是返回“刀”。 - Dylan Pierce
1
@DylanPierce 使用 slice! 实现这个功能非常容易。 my_string.slice!(my_slice) my_string - Bennett Talpers
1
啊,没错,bang-ifying 是 Ruby 修改现有变量的方式。谢谢 @BennettTalpers。 - Dylan Pierce

4
如果你正在使用Rails或至少使用了ActiveSupport,那么你可以使用String#remove和String#remove!方法。
def remove!(*patterns)
  patterns.each do |pattern|
    gsub! pattern, ""
  end

  self
end

来源: http://api.rubyonrails.org/classes/String.html#method-i-remove

该方法移除字符串中的匹配项,并返回结果,原始字符串不被更改。它需要一个正则表达式或字符串参数作为匹配模式,可以选择传递可选的第二个参数,指定用于替换匹配项的字符串。


2
如果我理解正确的话,这个问题似乎要求对字符串执行减法(-)运算,即内置加号(+)运算(连接)的相反操作。
与先前的答案不同,我试图定义这样一个操作,必须遵守以下属性:
如果c = a + b,则c - a = b且c - b = a。
我们只需要三种内置的Ruby方法来实现这一点:
'abracadabra'.partition('abra').values_at(0,2).join == 'cadabra'。
我不会解释它的工作原理,因为可以逐个运行一个方法轻松理解。
这是一个概念证明代码:
# 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

如果您使用的是最新的 Ruby 版本(>= 2.0),这里有一个建议:使用 Refinements 来代替前面例子中的 String 猴子补丁。

做法很简单:

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

在需要使用它的块之前添加using MinusString


1
对于改进概念,点个赞。虽然在这种情况下猴子补丁字符串类可能有些过度,但有时我们确实需要猴子补丁,而改进的概念真的很适合它。 - wondersz1

-2

这是我会做的事情

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

多行格式化:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接