使用Ruby正则表达式进行搜索和替换

8

我在MySQL列中有一个文本blob字段,其中包含HTML。 我必须更改一些标记,所以我想我会在Ruby脚本中完成它。 这里与Ruby无关,但希望能看到使用Ruby的答案。 标记如下所示:

<h5>foo</h5>
  <table>
    <tbody>
    </tbody>
  </table>

<h5>bar</h5>
  <table>
    <tbody>
    </tbody>
  </table>

<h5>meow</h5>
  <table>
    <tbody>
    </tbody>
  </table>

我需要将每个文本的第一个<h5>foo</h5>块更改为<h2>something_else</h2>,同时保留其余部分不变。

使用Ruby似乎无法获得正确的PCRE正则表达式。


2
我恳求你考虑使用HTML解析器而不是正则表达式来处理HTML。正如之前很多, 很多, 很多次所说的那样,正则表达式解析器无法准确地解析HTML。 - Travis Kaufman
具体而言,我建议使用Nokogiri来加载您的HTML,对其进行操作,然后输出结果。 - Phrogz
3个回答

31
# The regex literal syntax using %r{...} allows / in your regex without escaping
new_str = my_str.sub( %r{<h5>[^<]+</h5>}, '<h2>something_else</h2>' )

使用 String#sub 替换 String#gsub 仅会导致第一个替换。如果你需要动态选择 'foo',你可以在正则表达式字面值中使用字符串插值:

new_str = my_str.sub( %r{<h5>#{searchstr}</h5>}, "<h2>#{replacestr}</h2>" )

不过,如果你知道 'foo' 是什么,那么你就不需要使用正则表达式:

new_str = my_str.sub( "<h5>searchstr</h5>", "<h2>#{replacestr}</h2>" )

甚至可以:

my_str[ "<h5>searchstr</h5>" ] = "<h2>#{replacestr}</h2>"

如果你需要运行代码来确定替换内容,可以使用sub的块形式:

new_str = my_str.sub %r{<h5>([^<]+)</h5>} do |full_match|
  # The expression returned from this block will be used as the replacement string
  # $1 will be the matched content between the h5 tags.
  "<h2>#{replacestr}</h2>"
end

6
每当我需要解析或修改HTML或XML时,我会使用解析器。除非完全没有其他选择,否则我几乎从不使用正则表达式或instring。以下是使用Nokogiri完成这项任务的方法,无需任何正则表达式:
text = <<EOT
<h5>foo</h5>
  <table>
    <tbody>
    </tbody>
  </table>

<h5>bar</h5>
  <table>
    <tbody>
    </tbody>
  </table>

<h5>meow</h5>
  <table>
    <tbody>
    </tbody>
  </table>
EOT

require 'nokogiri'

fragment = Nokogiri::HTML::DocumentFragment.parse(text)
print fragment.to_html

fragment.css('h5').select{ |n| n.text == 'foo' }.each do |n|
  n.name = 'h2'
  n.content = 'something_else'
end

print fragment.to_html

解析后,这就是Nokogiri从片段中返回的内容:

# >> <h5>foo</h5>
# >>   <table><tbody></tbody></table><h5>bar</h5>
# >>   <table><tbody></tbody></table><h5>meow</h5>
# >>   <table><tbody></tbody></table>

运行之后的结果:

# >> <h2>something_else</h2>
# >>   <table><tbody></tbody></table><h5>bar</h5>
# >>   <table><tbody></tbody></table><h5>meow</h5>
# >>   <table><tbody></tbody></table>

2

使用String.gsub方法和正则表达式<h5>[^<]+<\/h5>

>> current = "<h5>foo</h5>\n  <table>\n    <tbody>\n    </tbody>\n  </table>"
>> updated = current.gsub(/<h5>[^<]+<\/h5>/){"<h2>something_else</h2>"}
=> "<h2>something_else</h2>\n  <table>\n    <tbody>\n    </tbody>\n  </table>"

请注意,您可以在浏览器中舒适地测试Ruby正则表达式。 点击链接进行测试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接