Как удалить повторяющиеся пробелы в строке? - PullRequest
37 голосов
/ 05 февраля 2011

У меня есть строка:

"foo (2 пробела) bar (3 пробела) baaar (6 пробелов) fooo"

Как убрать в нем повторяющиеся пробелы, чтобы между любыми двумя словами не было больше одного пробела?

Ответы [ 7 ]

82 голосов
/ 05 февраля 2011

String # squeeze имеет необязательный параметр для указания символов для сжатия.

irb> "asd  asd asd   asd".squeeze(" ")
=> "asd asd asd asd"
44 голосов
/ 05 февраля 2011
>> str = "foo  bar   bar      baaar"
=> "foo  bar   bar      baaar"
>> str.split.join(" ")
=> "foo bar bar baaar"
>>
25 голосов
/ 30 декабря 2011

Обновленный бенчмарк из ответа @ 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

Что приводит к этим значениям при запуске на моем рабочем столе после его двойного запуска:

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)

Проблема в том, что squeezeудаляет любой повторяющийся символ, что приводит к другой выходной строке и не соответствует потребности OP.squeeze(' ') действительно удовлетворяет потребности, но замедляет его работу.

string.squeeze
 => "fo bar bar bar"

Я думал о том, как 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)

Итак, длинные строки имеют большое значение.


Если выиспользуйте 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)

Если вы хотите скорость, используйте gsub2.squeeze(' ') все равно будет обходить gsub реализацию.

21 голосов
/ 05 февраля 2011

В дополнение к другим ответам, обратите внимание, что оба Activesupport и Facets предоставляют String # squish (предостережение [update]: оно также удаляет новые строки в строке ):

>> "foo  bar   bar      baaar".squish
=> "foo bar bar baaar"
7 голосов
/ 05 февраля 2011

Используйте регулярное выражение для сопоставления повторяющихся пробелов (\s+) и замените его пробелом.

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

Это соответствует каждому пробелу, так как вы хотите заменить только пробелы, используйте / +/ вместо /\s+/.

"foo    bar  \nfoobar".gsub(/ +/, ' ')
=> "foo bar \nfoobar"
5 голосов
/ 06 февраля 2011

Какой метод работает лучше?

$ 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)
3 голосов
/ 05 февраля 2011

Просто используйте gsub и регулярное выражение. Например:

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

вернет новую строку или вы можете изменить str напрямую, используя gsub!.

КСТАТИ. Регулярные выражения очень полезны - в Интернете достаточно ресурсов, для тестирования собственных регулярных выражений, например, попробуйте rubular.com .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...