如何跨 HTML 个标签边界查找文本?
How to find text across HTML tag boundaries?
我有 HTML 这样的:
<div>Lorem ipsum <b>dolor sit</b> amet.</div>
如何在此 HTML 中为我的搜索字符串 ipsum dolor
找到基于纯文本的匹配项?我需要用于匹配的开始和结束 XPath 节点指针,以及指向这些开始和停止节点内部的字符索引。我使用 Nokogiri 来处理 DOM,但是 Ruby 的任何解决方案都可以。
难度:
我无法通过 DOM node.traverse {|node| … }
并在遇到文本节点时进行纯文本搜索,因为我的搜索字符串可以跨越标签边界。
将 HTML 转换为纯文本后,我无法进行纯文本搜索,因为我需要 XPath 索引作为结果。
我可以通过基本的树遍历自己实现它,但在我这样做之前,我想问一下是否有 Nokogiri 函数或技巧可以更轻松地完成它。
你可以这样做:
doc.search('div').find{|div| div.text[/ipsum dolor/]}
最终我们使用的代码如下。它针对问题中给出的示例显示,但也适用于任意深度 HTML 标记嵌套的一般情况。 (这是我们需要的。)
此外,我们以一种可以忽略一行中多余(≥2)个空白字符的方式实现它。这就是为什么我们必须搜索匹配的结尾而不能只使用搜索字符串/引号的长度和匹配位置的开始:搜索字符串和搜索匹配中的空白字符数可能不同。
doc = Nokogiri::HTML.fragment("<div>Lorem ipsum <b>dolor sit</b> amet.</div>")
quote = 'ipsum dolor'
# (1) Find search string in document text, "plain text in plain text".
quote_query =
quote.split(/[[:space:]]+/).map { |w| Regexp.quote(w) }.join('[[:space:]]+')
start_index = doc.text.index(/#{quote_query}/i)
end_index = start_index+doc.text[/#{quote_query}/i].size
# (2) Find XPath values and character indexes for our search match.
#
# To do this, walk through all text nodes and count characters until
# encountering both the start_index and end_index character counts
# of our search match.
start_xpath, start_offset, end_xpath, end_offset = nil
i = 0
doc.xpath('.//text() | text()').each do |x|
offset = 0
x.text.split('').each do
if i == start_index
e = x.previous
sum = 0
while e
sum+= e.text.size
e = e.previous
end
start_xpath = x.path.gsub(/^\?/, '').gsub(
/#{Regexp.quote('/text()')}.*$/, ''
)
start_offset = offset+sum
elsif i+1 == end_index
e = x.previous
sum = 0
while e
sum+= e.text.size
e = e.previous
end
end_xpath = x.path.gsub(/^\?/, '').gsub(
/#{Regexp.quote('/text()')}.*$/, ''
)
end_offset = offset+1+sum
end
offset+=1
i+=1
end
end
此时,我们可以为搜索匹配的开始和结束检索所需的 XPath 值(此外,字符偏移量指向搜索开始和结束的 XPath 指定元素内的确切字符比赛)。我们得到:
puts start_xpath
/div
puts start_offset
6
puts end_xpath
/div/b
puts end_offset
5
我有 HTML 这样的:
<div>Lorem ipsum <b>dolor sit</b> amet.</div>
如何在此 HTML 中为我的搜索字符串 ipsum dolor
找到基于纯文本的匹配项?我需要用于匹配的开始和结束 XPath 节点指针,以及指向这些开始和停止节点内部的字符索引。我使用 Nokogiri 来处理 DOM,但是 Ruby 的任何解决方案都可以。
难度:
我无法通过 DOM
node.traverse {|node| … }
并在遇到文本节点时进行纯文本搜索,因为我的搜索字符串可以跨越标签边界。将 HTML 转换为纯文本后,我无法进行纯文本搜索,因为我需要 XPath 索引作为结果。
我可以通过基本的树遍历自己实现它,但在我这样做之前,我想问一下是否有 Nokogiri 函数或技巧可以更轻松地完成它。
你可以这样做:
doc.search('div').find{|div| div.text[/ipsum dolor/]}
最终我们使用的代码如下。它针对问题中给出的示例显示,但也适用于任意深度 HTML 标记嵌套的一般情况。 (这是我们需要的。)
此外,我们以一种可以忽略一行中多余(≥2)个空白字符的方式实现它。这就是为什么我们必须搜索匹配的结尾而不能只使用搜索字符串/引号的长度和匹配位置的开始:搜索字符串和搜索匹配中的空白字符数可能不同。
doc = Nokogiri::HTML.fragment("<div>Lorem ipsum <b>dolor sit</b> amet.</div>")
quote = 'ipsum dolor'
# (1) Find search string in document text, "plain text in plain text".
quote_query =
quote.split(/[[:space:]]+/).map { |w| Regexp.quote(w) }.join('[[:space:]]+')
start_index = doc.text.index(/#{quote_query}/i)
end_index = start_index+doc.text[/#{quote_query}/i].size
# (2) Find XPath values and character indexes for our search match.
#
# To do this, walk through all text nodes and count characters until
# encountering both the start_index and end_index character counts
# of our search match.
start_xpath, start_offset, end_xpath, end_offset = nil
i = 0
doc.xpath('.//text() | text()').each do |x|
offset = 0
x.text.split('').each do
if i == start_index
e = x.previous
sum = 0
while e
sum+= e.text.size
e = e.previous
end
start_xpath = x.path.gsub(/^\?/, '').gsub(
/#{Regexp.quote('/text()')}.*$/, ''
)
start_offset = offset+sum
elsif i+1 == end_index
e = x.previous
sum = 0
while e
sum+= e.text.size
e = e.previous
end
end_xpath = x.path.gsub(/^\?/, '').gsub(
/#{Regexp.quote('/text()')}.*$/, ''
)
end_offset = offset+1+sum
end
offset+=1
i+=1
end
end
此时,我们可以为搜索匹配的开始和结束检索所需的 XPath 值(此外,字符偏移量指向搜索开始和结束的 XPath 指定元素内的确切字符比赛)。我们得到:
puts start_xpath
/div
puts start_offset
6
puts end_xpath
/div/b
puts end_offset
5