【问题标题】:How to find a word NOT inside <a> tag?如何在 <a> 标签内找到一个单词?
【发布时间】:2014-06-27 14:23:45
【问题描述】:

我需要正则表达式方面的帮助。我的任务与 twitter 的标签非常相似:我有一个字符串,其中包含以# 开头的单词。例如:

foo #bar hello

在将主题标签保存到数据库之前,我将其替换为链接并获取如下字符串:

foo <a href="bar">#bar</a>

在那之后,有时我需要重新解析字符串,我不想在&lt;a&gt; 标记内替换#bar 两次。我需要正则表达式,它应该找到一个以# 开头的单词,而不是放在&gt;&lt;&gt;&lt;/a&gt; 内。

【问题讨论】:

  • 这是foo &lt;a href="bar"&gt;#bar&lt;/a&gt;您的预期输出吗?
  • #bar 是否只有一层深?因为我认为我有一个解决方案,只要这些不嵌套在任何其他标签中。
  • 当然还有一个经典的问题,你考虑过xml解析器吗?
  • 要操作 HTML,您应该看看 Nokogiri gem:nokogiri.org
  • 不得不重新解析字符串让我觉得你没有很好地解决你的逻辑。在修改之前弄清楚字符串的所有更改,这样你只做一次,否则你会把自己画到角落里。

标签: ruby regex


【解决方案1】:

从您的输入中获取:

foo #bar hello

到你的输出:

foo <a href="bar">#bar</a> hello

幂等,所以你可以通过你的函数将你的输出传回并且它不会改变,你可以使用这个:

str1 = "foo #bar hello"
str2 = 'foo <a href="bar">#bar</a> hello'
replace_func = -> str { str.sub(/#(\w+)(?=[^<]*?(?:<[^\/]|$))/, '<a href="\1">#\1</a>')}
replace_func[str1]
replace_func[str2]
# both return: "foo <a href=\"bar\">#bar</a> hello"

Live Demo

此外,Nokogiri 可以非常简单地使用:

require 'nokogiri'
doc = Nokogiri::XML('<p>' + you_string + '</p>')
doc.search('//p').each do |node|
  node.content = node.content.sub(/#\w+/)
end

【讨论】:

    【解决方案2】:

    使用这个:

    /\<[^>]+\>[^<]*(\#[a-zA-Z]+)/
    

    [a-zA-Z] 是可以在# 之后的单词中的字母。如果您还想包含数字,您可以使用它:

    /\<[^>]+\>[^<]*(\#[a-zA-Z0-9]+)/
    

    【讨论】:

      【解决方案3】:

      Nokogiri 的主要优点是,如果文本节点没有链接节点作为祖先(链接不能嵌套),并且它包含至少有一个#(在其他文本节点内搜索也没用)

      require 'nokogiri'
      doc = Nokogiri::HTML(html_doc)
      
      doc.search('//text()[not(ancestor::a) and contains(., "#")]').each do |txt|
          txt.content.split(/(#\w+)/).each_with_index do |v, k|
              if k%2 > 0
                  node = Nokogiri::XML::Node.new("a", doc)
                  node.content = v
                  node['href'] = "http://domain.com?usr=" + v[1..-1]
              else
                  node = v
              end
              txt.before(node)
          end
          txt.remove
      end
      
      puts doc.to_html
      

      或更简单:

      doc.search('//text()[not(ancestor::a) and contains(., "#")]').each do |txt|
          txt.content.split(/(#\w+)/).each_with_index do |v, k|
              if k%2 > 0
                  v = '<a href="http://domain.com?usr=' + v[1..-1] + '">' + v + '</a>'
              end
              txt.before(v)
          end
          txt.remove
      end
      

      注意:如果您只需要处理完整 html 文档的部分内容,则必须稍作改动才能使其正常工作(您需要将 html 包装在根节点中,以使 XPath 查询正常工作)

      doc = Nokogiri::HTML::fragment('<div>' + html_doc + '</div>')
      doc.search('.//text()[not(ancestor::a) and contains(., "#")]').each do |txt|
      
          txt.content.split(/(#\w+)/).each_with_index do |v, k|
              if k%2 > 0
                  v = "<a href=\"http://mydomain.com?usr=#{v[1..-1]}\">#{v}</a>"
              end
              txt.before(v)
          end
          txt.remove
      end
      doc.xpath('*/node()').each do |node|
          puts node.to_html
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-20
        • 2013-09-12
        • 2022-01-26
        • 1970-01-01
        相关资源
        最近更新 更多