Как удалить повторяющиеся пробелы в строке?
У меня есть строка:
"foo (2 пробела) bar (3 пробела) baaar (6 пробела) fooo"
Как удалить повторяющиеся пробелы в нем, чтобы между любыми двумя словами не было больше одного пространства?
7 ответов
>> str = "foo bar bar baaar"
=> "foo bar bar baaar"
>> str.split.join(" ")
=> "foo bar bar baaar"
>>
строка#squeeze имеет необязательный параметр для указания символов для сжатия.
irb> "asd asd asd asd".squeeze(" ")
=> "asd asd asd asd"
обновленный бенчмарк из ответа @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
реализации хотя.
чтобы дополнить другие ответы, обратите внимание, что оба Activesupport и фасеток обеспечить строка#squish (обратите внимание, что он также удаляет символы новой строки в строку):
>> "foo bar bar baaar".squish
=> "foo bar bar baaar"
используйте регулярное выражение, чтобы соответствовать повторяющимся пробелам (\s+)
и замените его пробелом.
"foo bar foobar".gsub(/\s+/, ' ')
=> "foo bar foobar"
это соответствует каждому пробелу, так как вы хотите только заменить пробелы, используйте / +/
вместо /\s+/
.
"foo bar \nfoobar".gsub(/ +/, ' ')
=> "foo bar \nfoobar"
какой метод работает лучше?
$ 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)
просто использовать gsub
и regexp.
Например:
str = "foo bar bar baaar"
str.gsub(/\s+/, " ")
вернет новую строку или вы можете изменить str напрямую, используя gsub!
.
кстати. Regexp очень полезны - есть много ресурсов в интернете, для тестирования собственных regexpes попробуйте rubular.com например.