Cách dễ nhất để loại bỏ ký tự đầu tiên khỏi chuỗi là gì?


174

Thí dụ:

[12,23,987,43

Cách nhanh nhất, hiệu quả nhất để loại bỏ " [", sử dụng có thể một chop()nhưng cho ký tự đầu tiên là gì?


1
Tôi đã chỉnh sửa câu trả lời của mình để có thể thay đổi câu trả lời đã chọn của bạn. Xem bạn có thể trao giải cho câu trả lời của Jason Stirk không vì anh ấy là người nhanh nhất và rất dễ đọc.
Tin Man

3
Sử dụng str [1 ..- 1], nhanh nhất theo các câu trả lời dưới đây.
Achyut Rastogi

1
Kể từ Ruby 2.5, bạn có thể sử dụng delete_prefixdelete_prefix!- chi tiết bên dưới . Tôi đã không có thời gian để điểm chuẩn, nhưng sẽ làm sớm!
SRack

Cập nhật: Tôi đã điểm chuẩn các phương thức mới ( delete_prefix\ delete_prefix!) và chúng khá nhanh. Không hoàn toàn yêu thích tốc độ trước đây, nhưng khả năng đọc có nghĩa là chúng là những lựa chọn mới tuyệt vời để có!
SRack

Câu trả lời:


233

Tôi ủng hộ việc sử dụng một cái gì đó như:

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

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

Tôi luôn tìm cách nhanh nhất và dễ đọc nhất để làm mọi việc:

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

Chạy trên Mac Pro của tôi:

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)

Cập nhật để kết hợp thêm một câu trả lời được đề xuất:

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

Kết quả nào trong:

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)

Và một cách khác /^./để tìm ký tự đầu tiên:

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

Kết quả nào trong:

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

Đây là một bản cập nhật khác về phần cứng nhanh hơn và phiên bản mới hơn của 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)

Tại sao gsub lại chậm như vậy?

Sau khi thực hiện tìm kiếm / thay thế, gsubphải kiểm tra các kết quả bổ sung có thể có trước khi có thể biết liệu nó đã kết thúc chưa. subchỉ làm một và kết thúc. Hãy xem xét gsubnhư đó là tối thiểu hai subcuộc gọi.

Ngoài ra, điều quan trọng cần nhớ là gsub, và subcũng có thể bị vô hiệu hóa bởi regex được viết kém, khớp chậm hơn nhiều so với tìm kiếm chuỗi con. Nếu có thể neo regex để có được tốc độ cao nhất từ ​​nó. Có câu trả lời ở đây trên Stack Overflow chứng minh rằng hãy tìm kiếm xung quanh nếu bạn muốn biết thêm thông tin.


34
Điều quan trọng cần lưu ý là điều này sẽ chỉ hoạt động trong Ruby 1.9. Trong Ruby 1.8, điều này sẽ loại bỏ byte đầu tiên khỏi chuỗi, không phải ký tự đầu tiên, đây không phải là điều OP muốn.
Jörg W Mittag

+1: Tôi luôn quên rằng đến một vị trí chuỗi, bạn có thể chỉ định không chỉ một ký tự mà còn có thể chèn một chuỗi con. Cảm ơn!
quetzalcoatl

"[12,23,987,43".delete "["
rupweb

4
Điều đó xóa nó khỏi tất cả các vị trí, đó không phải là điều OP muốn: "... cho nhân vật đầu tiên?".
Tin Man

2
" what about "[12,23,987,43".shift ?"? Điều gì về "[12,23,987,43".shift NoMethodError: undefined method ca 'cho "[12,23,987,43": String`?
Tin Man

293

Tương tự như câu trả lời của Pablo ở trên, nhưng một chất tẩy rửa bóng râm:

str[1..-1]

Sẽ trả về mảng từ 1 đến ký tự cuối cùng.

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

13
+1 Hãy xem kết quả điểm chuẩn mà tôi đã thêm vào câu trả lời của mình. Bạn đã có thời gian chạy nhanh nhất, cộng với tôi nghĩ nó rất sạch sẽ.
Tin Man

Những gì về hiệu suất str[1,]so với ở trên?
Bohr

1
@Bohr: str[1,]trả lại cho bạn ký tự thứ 2 kể từ khi phạm vi là 1:nil. Bạn cần cung cấp độ dài tính toán thực tế hoặc thứ gì đó được đảm bảo cao hơn chiều dài, như, str[1,999999](dĩ nhiên sử dụng int_max) để có được toàn bộ đuôi. [1..-1]sạch hơn và có thể nhanh hơn, vì bạn không cần phải thao tác theo chiều dài thủ công (xem [1..length] trong điểm chuẩn)
quetzalcoatl

4
Giải pháp rất hay. Nhân tiện, nếu người ta muốn xóa các ký tự đầu tiên và cuối cùng:str[1..-2]
pisaruk

50

Chúng ta có thể sử dụng lát để làm điều này:

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

Sử dụng slice!chúng ta có thể xóa bất kỳ ký tự bằng cách chỉ định chỉ mục của nó.


2
Thanh lịch này slice!(0)thực sự nên là câu trả lời được lựa chọn, vì sử dụng asdf[0] = '' để loại bỏ ký tự đầu tiên là vô lý (giống như sử dụng gsub với regex và bắn một con ruồi bằng một khẩu súng lục).
f055

1
Mặc dù bề ngoài []=có vẻ không trực quan , nhưng không yêu cầu nhiều mã C bên dưới, nơi slice!yêu cầu công việc bổ sung. Điều đó cộng lại. Đối số có thể là "Cái nào dễ đọc hơn?" Tôi thấy việc sử dụng []=có thể đọc được, nhưng tôi đến từ nền C -> Perl có thể tô màu cho suy nghĩ của tôi. Các nhà phát triển Java có thể nghĩ rằng nó ít đọc hơn. Hoặc là một cách có thể chấp nhận để hoàn thành nhiệm vụ miễn là nó dễ hiểu và có thể bảo trì và không tải CPU quá mức.
Tin Man

Đồng ý. Bạn có biết làm thế nào chúng ta có thể đo lường được nếu một chức năng tải CPU nhiều trong ROR không? hoặc chúng ta nên sử dụng chênh lệch thời gian thực hiện tính bằng mili hoặc nano giây?
balanv

18

Ruby 2.5+

Kể từ Ruby 2.5, bạn có thể sử dụng delete_prefixhoặc delete_prefix!để đạt được điều này theo cách dễ đọc.

Trong trường hợp này "[12,23,987,43".delete_prefix("[").

Thêm thông tin ở đây:

'invisible'.delete_prefix('in') #=> "visible"
'pink'.delete_prefix('in') #=> "pink"

NB bạn cũng có thể sử dụng điều này để xóa các mục khỏi cuối chuỗi có delete_suffixdelete_suffix!

'worked'.delete_suffix('ed') #=> "work"
'medical'.delete_suffix('ed') #=> "medical"

Biên tập:

Sử dụng thiết lập điểm chuẩn của Tin Man, nó cũng có vẻ khá nhanh (dưới hai mục cuối delete_pdelete_p!). Không hoàn toàn pip các faves trước cho tốc độ, mặc dù rất dễ đọc.

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)


14

Nếu bạn luôn muốn loại bỏ dấu ngoặc hàng đầu:

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

Nếu bạn chỉ muốn xóa ký tự đầu tiên và bạn biết nó sẽ không nằm trong bộ ký tự đa nhân:

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

hoặc là

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

1
Tôi sẽ sử dụng "[12,23,987,43".sub(/^\[+/, "")thay vì gsub(/^\[/, ""). Công cụ đầu tiên cho phép công cụ regex tìm thấy tất cả các trận đấu sau đó chúng được thay thế trong một hành động và dẫn đến cải thiện tốc độ gấp đôi với Ruby 1.9.3.
Tin Man

1
Vì chúng ta đang làm việc với các chuỗi, điều này có nên gsub(/\A\[/, "") không?
Sagar Pandya

6

Thay thế không hiệu quả:

str.reverse.chop.reverse

4

Ví dụ: a = "Một hai ba"

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" 

Theo cách này, bạn có thể loại bỏ từng ký tự đầu tiên của chuỗi.


3
Điều này giống như câu trả lời của Jason Stirk chỉ được gửi từ nhiều tháng trước.
Tin Man

3

Cách dễ dàng:

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

removed = str[1..str.length]

Cách tuyệt vời:

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

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

(Lưu ý: thích cách dễ dàng :))


1
Nếu bạn muốn duy trì ngữ nghĩa "chặt", bạn chỉ có thể"[12,23,987,43".reverse.chop.reverse
Chris Heald

đó là một màn trình diễn khá lớn chỉ để lột xác một char
Pablo Fernandez

7
tại sao không sử dụng [1 ..- 1] thay vì [1..elf.length]?
Horseyguy

Ví dụ vá khỉ là khá tốt cho câu hỏi này, nó chỉ là IMO không liên quan và xấu xí.
dredozubov 17/03/2016

3

Cảm ơn @ the-tin-man đã kết hợp các tiêu chuẩn!

Than ôi, tôi không thực sự thích bất kỳ giải pháp nào trong số đó. Họ yêu cầu thêm một bước để có kết quả ( [0] = '', .strip!) hoặc họ không hiểu rõ về ngữ nghĩa / rõ ràng về những gì đang xảy ra ( [1..-1]: "Ừm, phạm vi từ 1 đến âm 1? Yearg?"), Hoặc chúng chậm hoặc dài viết ra ( .gsub, .length).

Những gì chúng tôi đang cố gắng là một "ca" (theo cách nói của Array), nhưng trả lại các ký tự còn lại, thay vì những gì đã bị thay đổi. Hãy sử dụng Ruby của chúng tôi để thực hiện điều này với các chuỗi! Chúng ta có thể sử dụng thao tác khung nhanh, nhưng đặt cho nó một cái tên hay và lấy một đối số để xác định mức độ chúng ta muốn vượt qua phía trước:

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

Nhưng có nhiều hơn chúng ta có thể làm với hoạt động khung nhanh nhưng khó sử dụng đó. Trong khi chúng ta đang ở đó, để hoàn thiện, hãy viết một #shift#firstcho Chuỗi (tại sao Array phải có tất cả niềm vui‽‽), lấy một đối số để chỉ định số lượng ký tự chúng ta muốn xóa từ đầu:

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

Ok, bây giờ chúng ta có một cách rõ ràng tốt để kéo các ký tự ra khỏi mặt trước của một chuỗi, với một phương thức phù hợp với Array#firstArray#shift(đó thực sự phải là một phương thức bang ??). Và chúng ta có thể dễ dàng có được chuỗi sửa đổi là tốt với #eat!. Hừm, chúng ta có nên chia sẻ eat!sức mạnh ing mới của mình với Array không? Tại sao không!

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

Bây giờ chúng ta có thể:

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

Cái đó tốt hơn!


2
Tôi nhớ một cuộc thảo luận nhiều năm trước trên các diễn đàn Perl về một chức năng như vậy với tên chip()thay vì chop()(và chimp()tương tự như chomp()).
Mark Thomas

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

str[0] = ""

7
Điều quan trọng cần lưu ý là điều này sẽ chỉ hoạt động trong Ruby 1.9. Trong Ruby 1.8, điều này sẽ loại bỏ byte đầu tiên khỏi chuỗi, không phải ký tự đầu tiên, đây không phải là điều OP muốn.
Jörg W Mittag

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

0

Sử dụng regex:

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

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

0

Tôi tìm thấy một giải pháp tốt str.delete(str[0])cho khả năng đọc của nó, mặc dù tôi không thể chứng thực về hiệu suất của nó.


0

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

# => [2,3,4]

Danh sách giảm một hoặc nhiều phần tử từ đầu mảng, không làm thay đổi mảng và trả về mảng thay vì phần tử bị bỏ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.