如何从Ruby中的字符串中删除子字符串?

时间:2014-12-18 16:58:05

标签: ruby

我有以下字符串,我想删除包含标记本身的<EMAIL>标记之间的所有内容:

"Great, I will send you something at 888@gmail.com.\n    <EMAIL><ADDRESS>T888@gmail.com</ADDRESS><SUBJECT>Quick note on 888@gmail.com</SUBJECT>\n      <BODY>Hi, just dropping you a quick note.</BODY></EMAIL>" 

我使用以下内容删除它:

string =  string.gsub(/<EMAIL>(.*)<\/EMAIL>/, '').strip

它不起作用。

当我从字符串中删除\n时(我不愿意,因为它会使格式化和输入更具限制性),然后我得到以下内容:

=> "Great, I will send you something at 888@gmail.com."

换句话说,当我删除它时它会起作用。

如何更改我的gsub语句以适应\ n以及为什么会导致失败?

2 个答案:

答案 0 :(得分:7)

您的字符串是多行的,但默认情况下,Ruby regexp逐行工作,因此<EMAIL></EMAIL>位于两个不同的行上,正则表达式永远不会匹配。

这是因为在默认模式下,元字符.代表除换行符之外的任何字符

您需要使用m(多行)标记:

s= "Great, I will send you something at 888@gmail.com.\n    <EMAIL><ADDRESS>T888@gmail.com</ADDRESS><SUBJECT>Quick note on 888@gmail.com</SUBJECT>\n      <BODY>Hi, just dropping you a quick note.</BODY></EMAIL>"=> "Great, I will send you something at 888@gmail.com.\n    <EMAIL><ADDRESS>T888@gmail.com</ADDRESS><SUBJECT>Quick note on 888@gmail.com</SUBJECT>\n      <BODY>Hi, just dropping you a quick note.</BODY></EMAIL>"
s.gsub(/<EMAIL>(.*)<\/EMAIL>/m, '').strip

返回:

"Great, I will send you something at 888@gmail.com."

答案 1 :(得分:2)

您正在做什么 可以工作,但它非常脆弱,因此不建议使用 相反,请使用Nokogiri之类的解析器:

require 'nokogiri'

str = "Great, I will send you something at 888@gmail.com.\n    <EMAIL><ADDRESS>T888@gmail.com</ADDRESS><SUBJECT>Quick note on 888@gmail.com</SUBJECT>\n      <BODY>Hi, just dropping you a quick note.</BODY></EMAIL>"

以下是解析文档的方法:

doc = Nokogiri::XML::DocumentFragment.parse(str)

如果字符串是有效的XML,我可以使用更短的方法来解析:

doc = Nokogiri::XML(str)

现在找到并删除标签及其内容:

doc.at('EMAIL').remove
puts doc.to_xml
# >> Great, I will send you something at 888@gmail.com.

at使用CSS选择器查找名为<EMAIL>的第一个标记。还有其他相关方法可以找到所有匹配的标记或特定于CSS或XPath选择器。

XML / HTML解析器将文本分解为节点,便于查找和操作它们。文本可以更改,只要它是有效的HTML或XML,正确编写的代码将继续工作。

查看强制性的&#34; RegEx match open tags except XHTML self-contained tags&#34;。

如果存在嵌入的重复标记,则正则表达式会严重崩溃,例如:

<b>bold <i>italic <b>another bold</b></i></b>

尝试仅使用模式剥离<b>标记会很痛苦。使用解析器更容易完成。

如果我在没有使用解析器的情况下完全坚持并且决定这样做,那么这将起作用:

foo = "Great, I will send you something at 888@gmail.com.\n <EMAIL><ADDRESS>asdf</ADDRESS><SUBJECT>sdfg</SUBJECT>\n <BODY>dfgh</BODY></EMAIL>" 
foo.gsub(%r#<EMAIL>.*?</EMAIL>#im, '').strip
# => "Great, I will send you something at 888@gmail.com."

或者:

foo.gsub(%r#\s*<EMAIL>.*?</EMAIL>\s*#im, '')
# => "Great, I will send you something at 888@gmail.com."

我更喜欢这两个中的第一个,因为它在视觉上更清晰。

使用i标志使模式不区分大小写:它会匹配<email><EMAIL>。使用m标记允许.将行尾视为普通字符。默认情况下将它们视为特殊情况,这使得带有嵌入式行尾的字符串被视为多行。

  

我不愿意,因为它会使格式化和输入更具限制性

有时在模式中删除类似尾随换行符的内容会更容易,然后再重新添加。如果选择在维护一些Ruby代码或复杂模式之间,我会选择Ruby代码。模式是强大的,我使用它们,但它们并不是一切的答案。