如何用另一个字符串替换特定字符串?

时间:2013-11-14 10:42:44

标签: ruby nokogiri

我从XML文件中读取了一些内容:

page_content = doc.xpath("/somenode/body").inner_text

此内容包含一些数据:

<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>

正如您所看到的,一些内容包含两对双引号。

我想要的结果是用一对替换两对双引号:

<p> Hello World, "How are you today"
<a href="www.hello.comm">Hello</a>
etc.
</p>

我试过的是:

page_content.gsub!(/[""]/, '"')
page_content.gsub!("\"\"", '"')

这似乎没有完成这项工作。关于如何获得我想要的结果的任何建议?

4 个答案:

答案 0 :(得分:3)

理解像Nokogiri这样的解析器是如何工作的很重要。

为了帮助您,它会尝试修复损坏/格式错误的HTML或XML。你的HTML格式不正确,所以当Nokogiri解析它时,它会被修复,但是,这个过程可以使Nokogiri进一步破坏HTML。为了避免这种情况,我们有时必须在将内容交给Nokogiri之前对其进行预处理,或者之后我们必须通过替换节点来解开内容。

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>
EOT

将HTML解析为DOM。

doc.at('p').to_html 
# => "<p> Hello World, \"\"How are you today\"\"\n<a href=\"\" www.hello.comm>Hello</a>\netc.\n</p>"

文本""How are you today""在没有任何修改的情况下处理,因为它是文本节点:

doc.at('p').child.class # => Nokogiri::XML::Text
doc.at('p').child.content # => " Hello World, \"\"How are you today\"\"\n"

解析后很容易修复:

doc.at('p').child.content = doc.at('p').child.content.gsub('""', '"')
# => " Hello World, \"How are you today\"\n"

尝试修复<a>标记的参数是一个完全不同的故事,因为到那时,Nokogiri修正了双引号,导致标记错误:

doc.at('a').to_html
# => "<a href=\"\" www.hello.comm>Hello</a>"

请注意,www.hello.comm已在其包含引号之外被提升。

要解决此问题,需要在将HTML传递给Nokogiri之前进行一些预处理,或者修复节点并用固定的节点替换损坏的节点。

以下是预处理<a>标记的基础:

html = <<EOT
<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>
EOT

html.gsub(/href=""([^"]+)""/, 'href="\1"')
# => "<p> Hello World, \"\"How are you today\"\"\n<a href=\"www.hello.comm\">Hello</a>\netc.\n</p>\n"

如果你走那条路,不要花哨。编写小的原子更改,以避免在HTML更改时破坏模式。

一种更健壮的方式(“健壮”的方式比我们通常使用解析器的方式要小一些):

bad_a = doc.at('a')
fixed_a = bad_a.to_html.gsub(/""\s([^>]+)>/, '"\1">')
bad_a.replace(fixed_a)
doc.at('p')
# => #(Element:0x3fe4ce9de9e4 {
#      name = "p",
#      children = [
#        #(Text " Hello World, \"How are you today\"\n"),
#        #(Element:0x3fe4ce9e0fdc {
#          name = "a",
#          attributes = [
#            #(Attr:0x3fe4ce9e0fa0 {
#              name = "href",
#              value = "www.hello.comm"
#              })],
#          children = [ #(Text "Hello")]
#          }),
#        #(Text "\netc.\n")]
#      })

doc.at('p').to_html
# => "<p> Hello World, \"How are you today\"\n<a href=\"www.hello.comm\">Hello</a>\netc.\n</p>"

可以使用毯子gsub按摩文本,但是在大型/复杂文档中存在附带损害的高风险。想象一下,如果

,文档会发生什么
html.gsub('""', '"')
当有许多标签包含空字符串时使用

<input value="" name="foo"><input value="" name="bar">

搜索/替换的结果将是:

<input value=" name="foo"><input value=" name="bar">

这几乎没有改善,反而会进一步严重破坏文件。

相反,最好通过手术解决问题。回到网络的黑暗,早期,开拓时期,我们曾经看到大量的格式错误的内容,并且必须使用正则表达式来处理它是正常的攻击计划。现在,通过解析器,我们通常可以避免它并且可以隔离问题并选择性地修复我们想要的内容。查看执行此操作所需的代码表明,正确执行此操作并不需要太多。

答案 1 :(得分:0)

page_content.gsub!('\"\"', '"')

答案 2 :(得分:-1)

page_content.gsub!(/"{2}/, '"')

rubular.com

答案 3 :(得分:-1)

a='<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>'

a.gsub! '""', '"'

[19] pry(main)> puts a
<p> Hello World, "How are you today"
<a href="www.hello.comm">Hello</a>
etc.
</p>