我是红宝石初学者,我发现了一个问题,我想知道是否有更多的'红宝石方式' 解决它。
我的问题是: 我有一个字符串,像这样:
str = "<div class=\"yui-u first\">\r\n\t\t\t\t\t<h1>Jonathan Doe</h1>\r\n
\t\t\t\t\t<h2>Web Designer, Director</h2>\r\n\t\t\t\t</div>"
# now, i want to replace the substring in <h1> </h1> and <h2> and </h2> with
these two string:"fooo" and "barr".
这就是我所做的:
# first, i got the exactly matched substrings of str:
r = str.scan(/(?<=<h\d>).*?(?=<\/h\d>)/)
# then, i create a hash table to set the corresponding replace strings
h = {r[0] => 'fooo', r[1] => 'barr'}
# finally, using str.gsub to replace those matched strings
str.gsub!(/(?<=<h\d>).*?(?=<\/h\d>)/, h)
# or like this
str.gsub!(/(?<=<h\d>).*?(?=<\/h\d>)/) {|v| h[v]}
PS:<h1> </h1>
和<h2> </h2>
中的子字符串不是固定的,所以我有
首先获取这些字符串,以便我可以构建一个哈希表。但是我
真的不喜欢上面的代码(因为我写了两行几乎相同),
我认为必须有一种优雅的方式来做到这一点。我尝试过这样的事情:
str.gsub!(/(?<=<h\d>).*?(?=<\/h\d>)/) { ['fooo', 'barr'].each {|v| v}}
但这不起作用。因为这个块每天都会返回['fooo','barr']! 如果有办法让这个块(或其他东西?)一次返回一个元素(第一次返回'fooo',然后在第二次返回'barr'),我的问题将解决! 谢谢!
答案 0 :(得分:1)
虽然您确实没有业务parsing HTML with a regexp,但像Nokogiri这样的库可以让您更容易直接修改DOM,但您所犯的错误在于假设迭代器每次替换只执行一次,并且该块只返回一个值。 each
实际上将返回正在迭代的对象。
这是一种避免所有正则表达式疯狂的方法:
require 'rubygems'
gem 'nokogiri'
require 'nokogiri'
str = "<div class=\"yui-u first\">\r\n\t\t\t\t\t<h1>Jonathan Doe</h1>\r\n
\t\t\t\t\t<h2>Web Designer, Director</h2>\r\n\t\t\t\t</div>"
html = Nokogiri::HTML(str)
h1 = html.at_css('h1')
h1.content = 'foo'
h2 = html.at_css('h2')
h2.content = 'bar'
puts html.to_s
如果你想做多个替换,每个替换得到一个不同的值,简单的方法就是从堆栈中删除值:
subs = %w[ foo bar baz ]
string = "x x x"
string.gsub!(/x/) do |s|
subs.shift
end
puts string.inspect
# => "foo bar baz"
请注意,此处会使用subs
。一种更有效的方法是增加某种索引变量并使用该值,但这是一个微不足道的修改。