2012-02-22 42 views
3

我正在制作一个使用ROR的基本讨论板。当用户发布对消息的响应时,输入的textarea会使用标签预先填充引号中的消息:[QUOTE]。由于这种格式是:找到嵌套开启和关闭标签的最佳方法

[QUOTE]引述消息放在这里[/ QUOTE]

目前,我有一个简单的解决方案,取代[QUOTE]和[/ QUOTE]使用HTML message.sub('[QUOTE]','html here here')只要[QUOTE]或[/ QUOTE]仍然存在。当我回复引用的消息时,我将HTML转换回[QUOTE]标签以确保预填充的输入textarea在其中没有HTML。因此,报价的报价,看起来像:

[QUOTE] [QUOTE]这里引述消息[/ QUOTE] [/ QUOTE]

这是问题所在。如果我再次运行我目前的方法,我会喜欢重复的HTML字段:

<div class='test'><div class='test'>quoted message goes here</div></div> 

相反,我希望能有一个解决方案,看起来像:

<div class='test1'><div class='test2'>quoted message goes here</div></div> 

等等.. 。 有关循环此最佳方法的任何建议?

回答

5

如果你想要做深入的跟踪,你必须使用gsub块方法:

text = "[QUOTE][QUOTE]quoted message here[/QUOTE][/QUOTE]" 

quote_level = 0 

new_text = text.gsub(/\[\/?QUOTE\]/) do |m| 
    case (m) 
    when '[QUOTE]' 
    quote_level += 1 
    "<div class='test#{quote_level}'>" 
    when '[/QUOTE]' 
    quote_level -= 1 
    "</div>" 
    end 
end 

puts new_text.inspect 
# => "<div class='test1'><div class='test2'>quoted message here</div></div>" 

处理无效的嵌套对时,你可以让这个更稳健,但对于格式良好的标签,这应该起作用。

+0

这看起来很完美!既然你提到它,我很好奇你将如何使用这个解决方案来处理无效的嵌套对? – Marc 2012-02-22 20:18:50

+1

你必须确保'quote_level'在任何时候都不会低于零,这意味着你已经关闭了太多,并且在转换结束时它正好是'0',否则你会有未封闭的标签。 – tadman 2012-02-22 21:02:44

1

这里有一个想法:

就拿这个表达式

(\[QUOTE\])(.*?)(\[\/QUOTE\]) 

并将其应用到您的字符串。它将匹配开始标签,结束标签和内容。然后取出内容并再次应用正则表达式。如果有任何匹配,这将是您的第二层嵌套。重复,而有匹配。

演示在这里:http://rubular.com/r/MkGsnUj3vL

+1

@tadman:该死的,我知道这个!谢谢,队友:) – 2012-02-22 20:11:08

+0

我检查了你的例子,我认为它只能巧合使用。如果你稍微修改它,它将使用'。*'贪婪匹配器,并为你留下一个无与伦比的'... [/ QUOTE] [QUOTE] ...'中间对。 '。*?'通常是比较安全的方式,即使它不擅长捕捉嵌套对也是如此。 – tadman 2012-02-22 20:12:14

+1

我认为你应该更新你的正则表达式到'(\ [QUOTE \])(?!\ [QUOTE \])(。*?)(\ [\/QUOTE \])''。请注意增加的负向预测。这样你就不会将两个打开的'[QUOTE]'匹配到一个关闭'[/ QUOTE]'。 (第一场比赛返回) – Luke 2015-09-23 19:01:23