我需要正则表达式的帮助。我的任务与twitter的主题标签非常相似:我有一个字符串,其中的单词与#
一起盯着。例如:
foo #bar hello
我在保存到数据库之前用链接替换hashtags并得到这样的字符串:
foo <a href="bar">#bar</a>
之后有时我需要重新解析字符串,我不想两次替换#bar
标记内的<a>
。我需要regexp,它应该找到以#
开头并且不在>
,<
,>
和</a>
内的单词。
答案 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"
此外,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]+)/