我有这样的HTML:
<div>Lorem ipsum <b>dolor sit</b> amet.</div>
如何在此HTML中为我的搜索字符串ipsum dolor
找到基于纯文本的匹配项?我需要匹配的开始和结束XPath节点指针,以及指向这些开始和停止节点内的字符索引。我使用Nokogiri来处理DOM,但Ruby的任何解决方案都很好。
难度:
我不能node.traverse {|node| … }
通过DOM并在文本节点遇到时进行纯文本搜索,因为我的搜索字符串可以跨越标记边界。
将HTML转换为纯文本后,我无法进行纯文本搜索,因为我需要使用XPath索引。
我可以通过基本的树遍历来实现它,但在此之前我会问是否有Nokogiri函数或技巧可以更舒适地完成它。
答案 0 :(得分:1)
您可以执行以下操作:
doc.search('div').find{|div| div.text[/ipsum dolor/]}
答案 1 :(得分:0)
最后,我们使用了如下代码。它显示了问题中给出的示例,但也适用于任意深度HTML标记嵌套的一般情况。 (这就是我们需要的。)
此外,我们以一种可以忽略连续多余(≥2)个空白字符的方式实现它。这就是我们必须搜索匹配结束并且不能仅使用搜索字符串/引号的长度和匹配位置的开始的原因:搜索字符串和搜索匹配中的空白字符数可能不同。
doc = Nokogiri::HTML.fragment("<div>Lorem ipsum <b>dolor sit</b> amet.</div>") quote = 'ipsum dolor' # 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 # Find XPath values and character indexes for start and stop of search match. # For that, walk through all text nodes and count characters until reaching # the start and end positions of the 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