正则表达式在尊重CDATA时转义HTML&符号

我编写了一个内容管理系统,该系统使用服务器端正则表达式在页面响应中将符号转发到客户端浏览器之前。 正则表达式注意到已经被转义或属于HTML实体的&符号。 例如,以下内容:

  a&b,c&  d,©  2009年 

改为:

  a&  b,c&  d,©  2009年 

(只有第一个&被修改。)这是正则表达式,它是从Rails助手中获取和修改的:

 html.gsub(/&(?!([a-zA-Z][a-zA-Z0-9]*|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] } 

虽然这很好用但确实有问题。 正则表达式不知道可能围绕未转义的&符号的任何<![CDATA[]]> 。 这对于嵌入式JavaScript保持不变是必要的。 例如,这个:

  //   

遗憾的是这样呈现:

  //   

这当然是JavaScript引擎无法理解的。

我的问题是:有没有办法修改正则表达式完全像现在这样做,除了它保持CDATA部分内的文本不变?

由于正则表达式开头并不那么简单,这个问题可能更容易回答:是否可以编写一个正则表达式,将所有字母更改为除“ < ”和“ > ”之间的字母之外的句点? 例如,一个会将"some are "更改为".... ... "

你自找的! :d

 /&(?!(?:[a-zA-Z][a-zA-Z0-9]*|#\d+);) (?!(?>(?:(?!).)*)\]\]>)/xm 

第一行是你原来的正则表达式。 如果前面有一个CDATA结束序列( ]]> ),前瞻匹配,除非这里和那之间有一个开放序列( )。 假设文档格式最小,那应该意味着当前位置在CDATA部分内。

哎呀,我倒退了:通过使用正向前瞻我只在CDATA部分匹配“裸”&符号。 我将它改为负面的前瞻,所以现在它正常工作。

顺便说一句,这个正则表达式在Ruby模式下的RegexBuddy中工作,但不在rubular站点 。 我怀疑Rubular使用旧版本的Ruby,并且支持不太强大的正则表达式; 任何人都可以证实吗? (您可能已经猜到了,我不是Ruby程序员。)

编辑:Rubular的问题是我使用's'作为修饰符(意思是点匹配 - 一切),但Ruby使用'm'。

不要使用正则表达式。 这是一个可怕而可怕的想法。 相反,只需HTML编码您输出的任何可能包含字符的内容。 像这样:

 require 'cgi' print CGI.escape("All of this is HTML encoded!") 

那很有效! 在Rubular,我不得不将选项从/xs更改为/m (我删除了正如你在上面展示的那样分隔正则表达式的两个部分的空格)。

您可以在http://www.rubular.com/regexes/5855上看到此正则表达式以及示例字符串。

如果Rubular永久链接不是永久性的,那么我就是为正则表达式输入的:

 /&(?!(?:[a-zA-Z][a-zA-Z0-9]*|#\d+);)(?!(?>(?:(?!).)*)\]\]>)/m 

这是测试字符串:

 

a & b

c & d

a & b

c & d

只有两个符号匹配 – 顶部的a & b和底部的a & b&符号已经逃脱了& 并且]]>之间的所有&符号(转义或不转义)都保持不变。

所以,我的最终代码现在是这样的:

 html.gsub(/&(?!(?:[a-zA-Z][a-zA-Z0-9]*|#\d+);)(?!(?>(?:(?!).)*)\]\]>)/m, '&') 

非常感谢Alan。 这正是我所需要的。

我在这里做了类似的事情:
编码XML文本数据的最佳方法

幸运的是,就我而言,CDATA不是问题。

有什么问题是你必须要小心,表达式不是贪婪的,或者你最终会得到这样的东西:

.... are < safe! >

我非常怀疑你想要完成的是你可以单独使用正则表达式做的事情。 Regexp在正确处理嵌套方面非常糟糕。

您最好使用XML解析器而不是转发CDATA内容。