巧解 JavaScript 中的嵌套替换
网友wys提问:如何仅使用JavaScript支持的正则语法,将
1 2 3 4 | <p> <table> <p> <p> </table> <table> <p> <p> </table> <p> |
中<table>...</table>之间的<p>都替换为<br/>?
思考
该问题的难点之一在于JavaScript支持的正则特性实在有限。楼主已经想到了非JavaScript的解法,如下:
1
2 re=/(?<=<table.*?)(<p>)(?=.*?<\/table>)/gi;
alert (sourcestr.replace(re,"<br>"));嗯,思路大致是这样。较真起来,即使JavaScript支持逆序环视,上面答案并不能够如愿运行。原因是带有量词的逆序环视(即在
(?<=)里面使用?, *, +, {}这样的量词)是更高级的的语法,极少有语言能够支持(特例是.Net)。但是,像楼主这样的正则问题应该是很普便的一个问题,我们经常需要循环地替换一些内容。该如何解答呢?
思路一
阅读JavaScript的文档,我找到了lastIndex这样的东东。根据这个东东,我形成了这样的思路:
- 先按外层循环,找到第一组较大的匹配。正则代码是
<table[^>]*>[\s\S]*?<\/table>- 定位到这次匹配结束的起始位置,替换掉这一段字串中所有的
<p>。- 循环执行。
我觉得上述思路大致清晰,但是细节太多(每次匹配涉及3个位置点,一个长度),解起来并非从容不迫,最终的代码想必也不会赏心悦目;尤为重要的是,整个思路像是原始的 Crack,而不是高手的 Hack 。而且思路与正则关系不大。我决定换一条路。
思路二
关键是循环和嵌套。还好不是盗梦空间的深层递归。能否将匹配的内容保护起来,替换完之后再放回原位呢?
想到这里,就豁然开朗了。
思路:先找到所有的匹配内容,记路在数组inner中;
同时使用该正则,将原字串split为另一个数组wrapper;
一个重要的特点是,wrapper一定比inner多一个元素,它一一将inner项隔开,并处于最外层。wrapper 和 inner 的关系,就像是一个手掌的5根指头与4个指缝的关系。将中间的元素取出,记下位置,等处理完之后,再将所有的元素粘合在一起。就是这样简单。代码如下(为了让问题更有普使性,我稍改了一下源字串):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 <script type="text/javascript">
var str="<p> <table> <p> ,<p> </table> <p> <table> <p> <p> </table> <p> <table> <p> <p> </table>";
var patt=/<table[^>]*>[\s\S]*?<\/table>/i;
var wrapper_result=str.split(patt);
var inner_result = str.match(/<table[^>]*>[\s\S]*?<\/table>/ig);
var len=inner_result.length;
var final=wrapper_result[0];
for (i=0; i<len; i++)
{
tmp=inner_result[i].replace(/<p>/gi,"<br>");
final+=tmp+wrapper_result[i+1];
}
alert(final);
</script>贴图:
更新
果然是能人辈出,评论更精彩!请看评论中的这则代码:
1 alert(sourcestr.replace(/<table.*?\/table>/ig, function($1){return $1.replace(/<p>/ig,"<br>")}));PS: 本站刚刚添加了评论中代码的解析,可以贴代码了。格式见评论部分的图例显示。谢谢合作!

var str=” , “;
str = str.replace(/()(.*?)()/g,function(m,a,b,c){
return a+b.replace(//g,”")+c
});
alert(str);
感觉这样好像看起来代码简单点,虽然惰性加载会有点效率问题,但是不是很大的内容话这样好像
看着舒服点阿
[Reply]
leoner Reply:
September 11th, 2010 at 7:27 pm
晕,代码都被过滤掉了!
[Reply]
rex Reply:
September 11th, 2010 at 8:26 pm
1. 能否再贴一下代码?使用《code lang=”javascript”》code … 《/code》 这样的格式(半角空格)。
2. 本文中的代码,应该可以很轻易地移植为其它语言的代码的,不限限于javascript。
3. 回调函数美观,易用。谢谢leoner!
[Reply]
leoner Reply:
September 13th, 2010 at 12:47 pm
《code lang=”javascript”
var str=” , “;
str = str.replace(/()(.*?)()/g,function(m,a,b,c){
return a+b.replace(//g,”)+c
});
alert(str);
《/code》
[Reply]
leoner Reply:
September 13th, 2010 at 12:49 pm
算了,不贴了,跟下面的思路类似,就是首先用惰性匹配,然后嵌套replace
[Reply]
rex Reply:
September 13th, 2010 at 5:33 pm
已经修复。请看“Leave a comment”下面的代码示例。感谢合作!
[Reply]
谢谢博主的热情,提问几个小时就给出回复了。
csdn上有位高手,支的招很妙,我也贴出来供大家参考。
2
alert(sourcestr.replace(/<table.*?\/table>/ig, function($1){return $1.replace(/<p>/ig,"<pp>")}));
[Reply]
谢谢博主的热情,提问几个小时就给出回复了。
csdn上有位高手,支的招很妙,我也贴出来供大家参考。
[Reply]
rex Reply:
September 12th, 2010 at 1:05 am
@wys 赞!
[Reply]
No.30 Reply:
September 13th, 2010 at 9:38 am
确实很妙!
[Reply]
Snopo Reply:
September 13th, 2010 at 10:23 am
代码很精炼。
两次replace放一块还没有这样使用过,碰见此类问题,一般都分开写的。
学习了一招。多谢分享。
[Reply]
解决方法很精巧,str的处理果然有很多学问 谢谢lz
[Reply]
求教:
如何通过正则表达式,查找出一段文本中可能的htm/html链接,并将这些链接字符串xxxx用标签包起来,像这样:
xxxx
问题背景:
是一批文本格式的说明文件转为html文件,里面的链接字符串需要转换为可以点击的链接.
[Reply]
hunter3721 Reply:
September 13th, 2010 at 3:18 pm
晕,带标签的文本提交后会被解析…
[Reply]
rex Reply:
September 13th, 2010 at 5:33 pm
已经修复。请看“Leave a comment”下面的代码示例。
[Reply]
hunter3721 Reply:
September 20th, 2010 at 10:30 pm
恩,我把问题再描述一次:)
我的问题其实就是要把一段纯文本的文字,转化为html页面可查看的形式,里面的链接地址要转换成超链接形式.
由于场景中的链接只有.html和.htm后缀两种, 因此用正则替换变得可行.(我一般是使用UE的Perl正则替换功能).
但写这个正则替换我遇到了一些困难, 特来求助.
原始文本:
2
3
4
5
文本 link/after/space.htm
文本 文本:
link/in/a/outstanding/line.htm
文本http://absolute/link.html
目标文本:
2
3
4
5
6
7
文本 文本 文本
文本 <a href="link/after/separator.htm">link/after/space.htm</a>
文本 文本:
<a href="link/in/a/outstanding/line.htm">link/in/a/outstanding/line.htm</a>
文本<a href="http://absolute/link.html">http://absolute/link.html</a>
</pre>
[Reply]
Anonymous Reply:
September 20th, 2010 at 11:03 pm
关键是URL的提取。我使用的是近似的匹配:
$subject =~ s!([a-zA-Z0-9/.:]+html?)!<a href="$1">$1</a>!g;图示:
[Reply]
hunter3721 Reply:
September 20th, 2010 at 11:11 pm
非常感谢,我明天上班以后试试看
[Reply]
rex Reply:
September 21st, 2010 at 8:39 am
好,有问题的话请继续留言讨论。提取URL的正则可以根据具体情况作调整。 URL总的来说变化多多,当然有比较靠谱的正则可以匹配,但是太长太复杂。对于简单的数据,简单的正则就好。(在了解自己的数据的基础上)。
[Reply]