从字符串中删除第一个字符的最简单方法是什么?

示例:

[12,23,987,43
删除“[ ”的最快、最有效的方法是

什么? 使用可能的chop(),但第一个字符?

187354 次浏览

简单的方法:

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


removed = str[1..str.length]

厉害道:

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


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

(注意:更喜欢简单的方法:))

如果您总是想去除前导括号:

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

如果您只想删除第一个字符,并且知道它不在多字节字符集中:

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

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

我有点喜欢用这样的词:

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


p asdf
# >> "12,23,987,43"

我一直在寻找最快、最易读的做事方式:

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

在我的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)

更新以纳入另一个建议的答案:

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

其结果是:

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)

另一个使用/^./来查找第一个字符:

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

其结果是:

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

下面是关于更快的硬件和更新的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)

为什么GSUB这么慢?

执行搜索/替换后,gsub必须先检查可能的其他匹配项,然后才能判断是否已完成。sub仅执行一个匹配项并完成。考虑gsub,就像它是至少两个sub调用。

此外,重要的是要记住,gsubsub也可能受到编写得很差的正则表达式的限制,这些正则表达式的匹配速度比子字符串搜索慢得多。如果可能的话,锚定正则表达式以获得最快的速度。这里有关于堆栈溢出的答案,所以如果你想要更多的信息,可以搜索一下。

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


str[0] = ""

与上面Pablo的回答类似,但他是一个遮光罩清洁工:

str[1..-1]

将返回从1到最后一个字符的数组。

'Hello World'[1..-1]
=> "ello World"

例如:A=“一二三”

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"

通过这种方式,您可以逐个删除字符串的第一个字符。

我们可以使用Slice来执行以下操作:

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

使用slice!,我们可以通过指定其索引来删除任何字符。

感谢@The-Tin-Man整理基准!

唉,我真的不喜欢这些解决方案。要么他们需要额外的步骤来获得结果([0] = ''.strip!),要么他们不是非常语义/清楚所发生的事情([1..-1]:嗯,从1到负1的范围?或者它们写出来很慢或很长(.gsub.length)。

我们正在尝试的是“移位”(数组用语),但返回剩余的字符,而不是被移位的字符。让我们使用我们的Ruby通过字符串来实现这一点!我们可以使用快速括号操作,但要给它一个好的名称,并使用一个参数来指定我们想要从前面切掉多少:

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

但是我们可以用快速但笨拙的括号操作做更多的事情。在此过程中,为完整起见,让我们为字符串编写一个#shift#first(为什么数组应该拥有所有的乐趣),使用一个参数来指定我们要从开头删除多少字符:

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

好了,现在我们有了一个很好的清晰的方法来从字符串的前面提取字符,该方法与Array#firstArray#shift一致(这确实应该是一个好方法?)。我们可以很容易地得到修改后的字符串,以及#eat!。嗯,我们是否应该与阵列共享我们新的eat!ing电源?为什么不!

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

现在我们可以:

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

那更好!

我更喜欢这个:

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

效率低下的替代方案:

str.reverse.chop.reverse
class String
def bye_felicia()
felicia = self.strip[0] #first char, not first space.
self.sub(felicia, '')
end
end

使用正则表达式:

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


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

红宝石2.5+

从Ruby2.5开始,您可以使用delete_prefixdelete_prefix!以可读的方式实现这一点。

在这种情况下,"[12,23,987,43".delete_prefix("[")

更多信息请点击:

  • 官方文件

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

注意:您还可以使用此选项从__为ABC__0且__为ABC__1的字符串的末尾删除项目

'worked'.delete_suffix('ed') #=> "work"
'medical'.delete_suffix('ed') #=> "medical"
  • 文件
  • https://bugs.ruby-lang.org/issues/13665.

编辑:

使用Tin Man的基准测试设置,它看起来也相当快(在最后两个条目下delete_pdelete_p!)。不相当点以前的最爱的速度,虽然是非常可读的。

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)

我发现一个很好的解决方案是str.delete(str[0])的可读性,虽然我不能证明它的性能。

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

# => [2,3,4]

List从数组的开头删除一个或多个元素,不改变数组,并返回数组本身而不是删除的元素。