ChatGPT解决这个技术问题 Extra ChatGPT

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

例子:

[12,23,987,43

删除“[”的最快、最有效的方法是什么,可能使用 chop() 但第一个字符?

我编辑了我的答案,因此可能会更改您选择的答案。看看您是否可以将它授予 Jason Stirk 的答案,因为他是最快的,并且可读性很强。
使用 str[1..-1],根据下面的答案最快。
从 Ruby 2.5 开始,您可以使用 delete_prefixdelete_prefix! - more details below。我没有时间进行基准测试,但很快就会做!
更新:我对新方法 (delete_prefix \ delete_prefix!) 进行了基准测试,它们的速度非常快。在速度方面并没有完全超越以前的最爱,但可读性意味着它们是很好的新选择!

J
Jason Stirk

类似于上面巴勃罗的回答,但有一个阴影清洁剂:

str[1..-1]

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

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

+1 看看我添加到答案中的基准测试结果。您拥有最快的运行时间,而且我认为它非常干净。
与上述相比,str[1,] 的性能如何?
@Bohr:str[1,] 返回第二个字符,因为范围是 1:nil。您需要提供实际计算的长度,或者保证高于长度的东西,例如 str[1,999999] (当然使用 int_max )来获得整个尾巴。 [1..-1] 更简洁,可能更快,因为您不需要手动操作长度(请参阅基准中的 [1..length])
非常好的解决方案。顺便说一句,如果要删除第一个和最后一个字符:str[1..-2]
t
the Tin Man

我有点喜欢使用类似的东西:

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 也可能因编写不佳的正则表达式而受到阻碍,它们的匹配速度比子字符串搜索要慢得多。如果可能的话,锚定正则表达式以获得最快的速度。 Stack Overflow 上的答案表明,如果您想了解更多信息,请四处搜索。


需要注意的是,这只适用于 Ruby 1.9。在 Ruby 1.8 中,这将从字符串中删除第一个字节,而不是第一个字符,这不是 OP 想要的。
+1:我总是忘记,对于字符串位置,您不仅可以分配单个字符,还可以插入子字符串。谢谢!
"[12,23,987,43".delete "["
这会从所有位置删除它,这不是 OP 想要的:“......对于第一个字符?”。
what about "[12,23,987,43".shift ?”? "[12,23,987,43":String` 的 "[12,23,987,43".shift NoMethodError: undefined method shift' 怎么样?
C
Charlie Egan

我们可以使用 slice 来做到这一点:

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

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


这个优雅的 slice!(0) 确实应该是选择的答案,因为使用 asdf[0] = '' 删除第一个字符是荒谬的(就像使用 gsub 和正则表达式并用榴弹炮射击苍蝇一样)。
虽然表面上看起来不直观,但 []= 不需要那么多底层 C 代码,而 slice! 需要额外的工作。这加起来。争论可能是“哪个更具可读性?”我发现使用 []= 可读,但我来自 C --> Perl 背景可能会影响我的思考。 Java 开发人员可能会认为它的可读性较差。只要它易于理解和可维护并且不会过度加载 CPU,这两种方法都是可接受的完成任务的方式。
好的。你知道我们如何衡量一个函数在 ROR 中是否占用大量 CPU 负载吗?还是我们应该使用毫秒或纳秒的执行时间差?
S
SRack

红宝石 2.5+

从 Ruby 2.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"

注意,您还可以使用它从带有 delete_suffixdelete_suffix! 的字符串末尾删除项目

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

s
schmijos

我更喜欢这个:

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

您可能想在重复之前检查其他答案。 stackoverflow.com/a/3614642/128421 已建议这样做
C
Chris Heald

如果你总是想去掉前导括号:

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

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

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

或者

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

我会使用 "[12,23,987,43".sub(/^\[+/, "") 而不是 gsub(/^\[/, "")。第一个让正则表达式引擎找到所有匹配项,然后在一个操作中替换它们,并在 Ruby 1.9.3 中将速度提高约 2 倍。
既然我们正在处理字符串,这应该是 gsub(/\A\[/, "") 吗?
t
the Tin Man

低效的替代方案:

str.reverse.chop.reverse

R
Rubyist

例如: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" 

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


这与 Jason Stirk's answer 相同,只是他在几个月前提交。
P
Pablo Fernandez

简单的方法:

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

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


如果您想保留“chop”语义,您可以"[12,23,987,43".reverse.chop.reverse
这是一个相当大的性能开销,只是为了去掉一个字符
为什么不使用 [1..-1] 而不是 [1..self.length] ?
猴子修补示例对于这个问题来说很不合适,它只是无关紧要且丑陋的 IMO。
b
brookr

感谢@the-tin-man 将基准放在一起!

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

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

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

但是我们可以用这种快速但笨拙的支架操作做更多的事情。虽然我们在这里,为了完整起见,让我们为 String 编写一个 #shift#first(为什么 Array 应该有这么多乐趣‽‽),使用一个 arg 来指定我们要从开头删除多少个字符:

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 一致的方法(这真的应该是一个 bang 方法??)。我们也可以使用 #eat! 轻松获取修改后的字符串。嗯,我们应该与 Array 分享我们新的eat!力量吗?为什么不!

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] 

这样更好!


我记得几年前在 Perl 论坛上讨论过这样一个函数,名称为 chip() 而不是 chop()(并且 chimp()chomp() 类似)。
H
Handcraftsman
str = "[12,23,987,43"

str[0] = ""

需要注意的是,这只适用于 Ruby 1.9。在 Ruby 1.8 中,这将从字符串中删除第一个字节,而不是第一个字符,这不是 OP 想要的。
J
Josh Brody
class String
  def bye_felicia()
    felicia = self.strip[0] #first char, not first space.
    self.sub(felicia, '')
  end
end

费利西亚对你做了什么让你配得上这个代码俳句?
S
Sagar Pandya

使用正则表达式:

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

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

z
zeitchef

我发现一个很好的解决方案是str.delete(str[0]),因为它的可读性,但我无法证明它的性能。


A
Aaron Henderson

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

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