2011-02-05 35 views
34

Tôi có một chuỗi:Làm cách nào để xóa các khoảng trắng lặp lại trong chuỗi?

"foo (2 chỗ) bar (3 gian) baaar (6 chỗ) fooo"

Làm thế nào để loại bỏ không gian lặp đi lặp lại trong nó để không nên có nhiều hơn một khoảng trống giữa hai từ?

+2

Bạn biết đấy, loại câu hỏi này được trả lời dễ dàng bằng cách xem lại tất cả các phương thức String. Tôi khuyên bạn nên làm quen với tài liệu cho các phương thức String, Array và Enumerable. –

+0

Trong trường hợp bạn không biết bắt đầu từ đâu, hãy truy cập [http://ruby-doc.org/](http://ruby-doc.org/) và sau đó nhấp vào [API lõi] (http://ruby-doc.org/core) và sau đó nhấp vào lớp String ở cột giữa trên cùng. – Phrogz

+0

Để bảo vệ OP, việc loại bỏ các khoảng trống có thể được thực hiện theo nhiều cách, không phải tất cả đều là trực quan nhất, đặc biệt là khi bạn xem kết quả benchmark. –

Trả lời

38
>> str = "foo bar bar  baaar" 
=> "foo bar bar  baaar" 
>> str.split.join(" ") 
=> "foo bar bar baaar" 
>> 
+3

+1 Để có một cách thú vị để làm điều đó, nhưng -1 cho một đề nghị không hiệu quả so với khác, lựa chọn thay thế phù hợp hơn. – Phrogz

+2

@Phrogz. không hiệu quả? bất kỳ điểm chuẩn nào để chứng minh điều đó? – kurumi

+1

xem http://stackoverflow.com/questions/4907068/remove-repeated-spaces-in-ruby-string/4911709#4911709 :) – zetetic

7

Sử dụng cụm từ thông dụng để đối sánh khoảng trắng lặp lại (\s+) và thay thế bằng khoảng trắng.

"foo bar foobar".gsub(/\s+/, ' ') 
=> "foo bar foobar" 

này phù hợp với tất cả các khoảng trắng, vì bạn chỉ muốn thay thế không gian, sử dụng / +/ thay vì /\s+/.

"foo bar \nfoobar".gsub(/ +/, ' ') 
=> "foo bar \nfoobar" 
3

Chỉ cần sử dụng gsub và regexp. Ví dụ:

str = "foo bar bar  baaar" 
str.gsub(/\s+/, " ") 

sẽ trở lại chuỗi mới hoặc bạn có thể sửa đổi str trực tiếp sử dụng gsub!.

BTW. Regexp rất hữu ích - có rất nhiều tài nguyên trên internet, để thử nghiệm các quy trình của riêng bạn, hãy thử ví dụ rubular.com.

16

Để bổ sung cho câu trả lời khác, lưu ý rằng cả ActivesupportFacets cung cấp String#squish (lưu ý rằng nó cũng loại bỏ dòng mới trong chuỗi):

>> "foo bar bar  baaar".squish 
=> "foo bar bar baaar" 
+1

Hãy nhớ rằng '# squish' cũng loại bỏ các dòng mới. – moveson

75
irb> "asd asd asd asd".squeeze(" ") 
=> "asd asd asd asd" 

String#squeeze

+2

Không đúng ... nó có thể "làm hỏng" chuỗi ... ví dụ sẽ là "50b2a6cc6d5a2fb4e7000006" nơi bạn sẽ nhận được "50b2a6c6d5a2fb4e706". – xpepermint

+8

@xpepermint, lưu ý tham số '" "'. – Nakilon

+0

ow ... tôi đã bỏ lỡ, xin lỗi :) – xpepermint

5

Những phương pháp thực hiện tốt hơn?

$ ruby -v 
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux] 

$ cat squeeze.rb 
require 'benchmark' 
include Benchmark 

string = "foo bar bar  baaar" 
n = 1_000_000 
bm(6) do |x| 
    x.report("gsub  ") { n.times { string.gsub(/\s+/, " ") } } 
    x.report("squeeze ") { n.times { string.squeeze } } 
    x.report("split/join") { n.times { string.split.join(" ") } } 
end 

$ ruby squeeze.rb 
      user  system  total  real 
gsub  4.970000 0.020000 4.990000 ( 5.624229) 
squeeze  0.600000 0.000000 0.600000 ( 0.677733) 
split/join 2.950000 0.020000 2.970000 ( 3.243022) 
+2

điểm chuẩn này không hoàn toàn chính xác. 'string.squeeze =>" fo thanh bar bar "' mà tước bất kỳ ký tự lặp đi lặp lại. Thay đổi thành 'string.squeeze ('')' kết quả theo thời gian đặt nó vững chắc giữa 'gsub' và' split.join ('') ', với giá trị cuối cùng là nhanh nhất. Xem câu trả lời của tôi cho mã điểm chuẩn được cập nhật. –

23

điểm chuẩn Cập nhật từ câu trả lời @ zetetic của:

require 'benchmark' 
include Benchmark 

string = "foo bar bar  baaar" 
n = 1_000_000 
bm(12) do |x| 
    x.report("gsub  ") { n.times { string.gsub(/\s+/, " ") } } 
    x.report("squeeze(' ')") { n.times { string.squeeze(' ') } } 
    x.report("split/join") { n.times { string.split.join(" ") } } 
end 

nào dẫn đến những giá trị này khi chạy trên máy tính để bàn của tôi sau khi chạy nó hai lần:

ruby test.rb; ruby test.rb 
        user  system  total  real 
gsub   6.060000 0.000000 6.060000 ( 6.061435) 
squeeze(' ') 4.200000 0.010000 4.210000 ( 4.201619) 
split/join 3.620000 0.000000 3.620000 ( 3.614499) 
        user  system  total  real 
gsub   6.020000 0.000000 6.020000 ( 6.023391) 
squeeze(' ') 4.150000 0.010000 4.160000 ( 4.153204) 
split/join 3.590000 0.000000 3.590000 ( 3.587590) 

Vấn đề là squeeze loại bỏ bất kỳ lặp lại ký tự, kết quả trong một chuỗi đầu ra khác nhau và không đáp ứng nhu cầu của OP. squeeze(' ') không đáp ứng nhu cầu, nhưng làm chậm hoạt động của nó.

string.squeeze 
=> "fo bar bar bar" 

Tôi đã suy nghĩ về cách thức split.join có thể là nhanh hơn và nó không có vẻ như rằng sẽ tổ chức trong chuỗi lớn, vì vậy tôi điều chỉnh điểm chuẩn để xem những gì hiệu quả chuỗi dài sẽ có:

require 'benchmark' 
include Benchmark 

string = (["foo bar bar  baaar"] * 10_000).join 
puts "String length: #{ string.length } characters" 
n = 100 
bm(12) do |x| 
    x.report("gsub  ") { n.times { string.gsub(/\s+/, " ") } } 
    x.report("squeeze(' ')") { n.times { string.squeeze(' ') } } 
    x.report("split/join") { n.times { string.split.join(" ") } } 
end 

ruby test.rb ; ruby test.rb 

String length: 250000 characters 
        user  system  total  real 
gsub   2.570000 0.010000 2.580000 ( 2.576149) 
squeeze(' ') 0.140000 0.000000 0.140000 ( 0.150298) 
split/join 1.400000 0.010000 1.410000 ( 1.396078) 

String length: 250000 characters 
        user  system  total  real 
gsub   2.570000 0.010000 2.580000 ( 2.573802) 
squeeze(' ') 0.140000 0.000000 0.140000 ( 0.150384) 
split/join 1.400000 0.010000 1.410000 ( 1.397748) 

Vì vậy, đường dài tạo sự khác biệt lớn.


Nếu bạn sử dụng gsub sau đó gsub/\ s {2,} /, ' ') là nhanh hơn một chút.

Không thực sự. Đây là phiên bản của điểm chuẩn để kiểm tra xác nhận đó:

require 'benchmark' 
include Benchmark 

string = "foo bar bar  baaar" 
puts string.gsub(/\s+/, " ") 
puts string.gsub(/\s{2,}/, ' ') 
puts string.gsub(/\s\s+/, " ") 

string = (["foo bar bar  baaar"] * 10_000).join 
puts "String length: #{ string.length } characters" 
n = 100 
bm(18) do |x| 
    x.report("gsub")    { n.times { string.gsub(/\s+/, " ") } } 
    x.report('gsub/\s{2,}/, "")') { n.times { string.gsub(/\s{2,}/, ' ') } } 
    x.report("gsub2")    { n.times { string.gsub(/\s\s+/, " ") } } 
end 
# >> foo bar bar baaar 
# >> foo bar bar baaar 
# >> foo bar bar baaar 
# >> String length: 250000 characters 
# >>       user  system  total  real 
# >> gsub     1.380000 0.010000 1.390000 ( 1.381276) 
# >> gsub/\s{2,}/, "") 1.590000 0.000000 1.590000 ( 1.609292) 
# >> gsub2    1.050000 0.010000 1.060000 ( 1.051005) 

Nếu bạn muốn tốc độ, hãy sử dụng gsub2. squeeze(' ') sẽ vẫn chạy vòng tròn xung quanh việc thực hiện gsub.

+0

+1 tốt bắt sir – zetetic

+0

@ zetetic, tôi nghĩ Benchmark là một công cụ thiết yếu. Tôi không thể đếm bao nhiêu lần tôi đã giả định một cái gì đó sẽ là cách nhanh nhất để làm một nhiệm vụ cụ thể, và có điểm chuẩn chứng minh tôi sai. Tôi đã không bao giờ được coi là 'chia/join' để được nhanh nhất, mặc dù tôi đã sử dụng nó trong các ứng dụng cho mục đích này. –

+0

@zetetic, hãy kiểm tra kết quả kiểm tra đã thêm. –

Các vấn đề liên quan