如何在<a> tag?</a>内找到一个单词

时间:2014-06-27 14:23:46

标签: ruby regex

我需要正则表达式的帮助。我的任务与twitter的主题标签非常相似:我有一个字符串,其中的单词与#一起盯着。例如:

foo #bar hello

我在保存到数据库之前用链接替换hashtags并得到这样的字符串:

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

之后有时我需要重新解析字符串,我不想两次替换#bar标记内的<a>。我需要regexp,它应该找到以#开头并且不在><></a>内的单词。

3 个答案:

答案 0 :(得分:0)

从您的输入中获取:

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

答案 1 :(得分:0)

Nokogiri的主要优点是,如果文本节点没有链接节点作为祖先(链接不能嵌套)并且如果它包含,则可以轻松检查XPath查询至少有一个# (在其他文本节点中搜索没用)

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

答案 2 :(得分:0)

使用它:

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

[a-zA-Z]是#之后的单词中的字母。如果你想要包括数字,你也可以使用它:

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