如何删除字符串中的重复空格?

Kir*_*Kir 38 ruby

我有一个字符串:

"foo(2个空格)bar(3个空格)baaar(6个空格)fooo"

如何删除其中的重复空格,以便在任意两个单词之间不要超过一个空格?

Nak*_*lon 84

String#squeeze有一个可选参数来指定要挤压的字符.

irb> "asd  asd asd   asd".squeeze(" ")
=> "asd asd asd asd"
Run Code Online (Sandbox Code Playgroud)

  • @xpepermint,注意``"`参数. (12认同)
  • 不正确......它可以"破坏"字符串...例如"50b2a6cc6d5a2fb4e7000006",你会得到"50b2a6c6d5a2fb4e706". (2认同)
  • @xpepermint 是的,我刚刚被这个问题烧死并提出了这个问题 (2认同)

kur*_*umi 44

>> str = "foo  bar   bar      baaar"
=> "foo  bar   bar      baaar"
>> str.split.join(" ")
=> "foo bar bar baaar"
>>
Run Code Online (Sandbox Code Playgroud)

  • +1这是一种有趣的方式,但与其他更合适的替代方案相比,效率低的建议为-1. (3认同)
  • 好吧,你毕竟赢了+1 :)很高兴你要求证明. (3认同)
  • @Phrogz.效率低下?任何基准来证明这一点? (2认同)

the*_*Man 25

从@ zetetic的答案更新了基准:

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
Run Code Online (Sandbox Code Playgroud)

运行两次后,在桌面上运行时会产生这些值:

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)
Run Code Online (Sandbox Code Playgroud)

问题是squeeze删除任何重复的字符,这会导致不同的输出字符串,并且不符合OP的需要.squeeze(' ')确实满足了需求,但减慢了运营速度.

string.squeeze
 => "fo bar bar bar"
Run Code Online (Sandbox Code Playgroud)

我正在考虑如何split.join更快,并且似乎不会用大字符串,所以我调整基准测试以查看长字符串会产生什么影响:

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)
Run Code Online (Sandbox Code Playgroud)

因此,长线确实有很大的不同.


如果你确实使用gsub,那么gsub /\s {2,} /,'')会稍快一些.

并不是的.这是一个测试该断言的基准测试版本:

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)
Run Code Online (Sandbox Code Playgroud)

如果你想要速度,请使用gsub2.squeeze(' ')仍然会围绕一个gsub实现运行圈子.

  • @zetetic,我认为 Benchmark 是必不可少的工具。我数不清有多少次我假设某事将是完成特定任务的最快方式,并且有基准测试证明我错了。我从来没有考虑过“拆分/加入”是最快的,尽管我已经在应用程序中为此目的使用过它。 (2认同)

tok*_*and 21

要补充其他答案,请注意ActivesupportFacets都提供String#squish([update]警告:它还会删除字符串中的换行符):

>> "foo  bar   bar      baaar".squish
=> "foo bar bar baaar"
Run Code Online (Sandbox Code Playgroud)

  • 请记住,`#squish`也会删除换行符. (2认同)

Rei*_*cke 7

使用正则表达式匹配重复的空格(\s+)并用空格替换它.

"foo    bar  foobar".gsub(/\s+/, ' ')
=> "foo bar foobar"
Run Code Online (Sandbox Code Playgroud)

这匹配每个空格,因为您只想替换空格,/ +/而不是使用/\s+/.

"foo    bar  \nfoobar".gsub(/ +/, ' ')
=> "foo bar \nfoobar"
Run Code Online (Sandbox Code Playgroud)


zet*_*tic 5

哪种方法表现更好?

$ 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)
Run Code Online (Sandbox Code Playgroud)

  • 这个基准不太正确.`string.squeeze =>"fo bar bar bar"`它正在剥离任何重复的字符.更改为`string.squeeze('')`会导致将它牢固地放在`gsub`和`split.join('')`之间,最后一个是最快的.有关更新的基准代码,请参阅我的答案. (3认同)