歧义的正则替换

emu 2003-05-22 11:39:19
加精
要用一个正则将一个串中的单一个的数字改为两位的0?格式,在IE中不难:

s="1/01/2/3/4/04/5";
s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$10$2");
alert(s);

可是这样做在netScape6.0中就不行了,虽然根本不存在第10个匹配,netScape还是把$10看成是第10个匹配而不是第一个匹配加上“0”。

换种表达来避免歧义?

s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1\x30$2");

$1\x30$2居然也会被认为是$10$2!

那就试试把预查往前挪来避免歧义:

s = s.replace(/(?=\D|^)(\d)(\D|$)/g,"0$1$2");

结果不对啊?看看匹配结果:

s = s.match(/(?=\D)(\d)/g);

正向预查放到前面的时候根本不能匹配
用非存储匹配,又会丢失字符:

s = s.replace(/(?:^|\D)(\d)(\D|$)/g,"0$1$2");

怎么办?

暂时只能用两个正则先顶着:

s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1~$2").replace(/~/g,"0");

但是觉得不甘心,难道就没有办法用一个没有歧义的正则来完成这个功能吗?期待高手……
...全文
78 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
emu 2003-06-19
  • 打赏
  • 举报
回复
感谢cnlyl(海龙王)的热心支持,结帖!
emu 2003-06-04
  • 打赏
  • 举报
回复
-----------------------------------------------
所以说,统一浏览器还是大家所希望看到的事情。
-----------------------------------------------

恐怕我是个例外。如果真的统一了,以后linux从此不能上网了,桌面系统也就由微软一统天下了,这对大家有什么好处?是否接下来统一服务器平台,统一数据库平台,统一开发平台,也都会渐渐成为“大家希望看到的事情”呢?整个世界统一在一个以营利为目的的商业软件公司之下,你放心吗?

----------------------------------------------------------------
微软将淘汰单机IE浏览器 IE 6 SP1成最后版本
http://www.csdn.net/news/newstopic/11/11173.shtml
----------------------------------------------------------------

这样的统一是我们希望的吗?

wpoison 2003-06-04
  • 打赏
  • 举报
回复
要没有歧义,前面的几种写法都算是规范的没有歧义的写法了。但是问题不在这里,而是在各种不同的浏览器版本的bug上。所以说,统一浏览器还是大家所希望看到的事情。

呵呵,话题偏离技术了,我闪。
emu 2003-06-04
  • 打赏
  • 举报
回复
对不起,s = s.replace(/(^|\D)0*(\d)/g,"$1~$2").replace(/~/g,"0");是错的,不用预查恐怕不能正确的匹配。试试:

var s="01/11/21/31/4/04/5";
s = s.replace(/(^|\D)0*(\d)/g,"$1~$2").replace(/~/g,"0");

11变成011了,所以到现在正确的写法还是只有:

var s="01/11/21/31/4/04/5";
s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1~$2").replace(/~/g,"0");


emu 2003-06-04
  • 打赏
  • 举报
回复
按照cnlyl(海龙王)的方法在NS6.0下的写法应该为:

var s="01/1/2/3/4/04/5";
var cExpress = ( document.all ? "$10$2" : "$1$990$2" );
s = s.replace(/(^|\D)0*(\d)/g, cExpress );
document.write(s);

不过这个写法在ns4.7和ns7下面大概都不会对,难道我们还要对不同的版本各写一个?

毕竟我们不是想要一个将就着能通过的写法,不然

s = s.replace(/(^|\D)0*(\d)/g,"$1~$2").replace(/~/g,"0");

就已经够了。我们想要的是一个规范的通用的没有歧义的正则。
emu 2003-06-04
  • 打赏
  • 举报
回复
我真的不想看到你跳楼,可是,
var s="01/1/2/3/4/04/5";
var cExpress = ( document.all ? "$10$2" : "$1$9999999999" + "0$2" );
s = s.replace(/(^|\D)0*(\d)/g, cExpress );
document.write(s)

在netscape6.0下的运行结果是:

9999999901/9999999901/9999999902/9999999903/9999999904/9999999904/9999999905


你就安心的去吧,人民会想念你的 :)

$9999999999不是一个正规的正则写法,就算现在碰巧能通过了,也无法被接受为标准答案。

此外,cExpress = ( document.all ? "$10$2" : "$1$9999999999" + "0$2" ); 这个写法好奇怪,为什么不是 cExpress = ( document.all ? "$10$2" : "$1$99999999990$2" ); 呢?是否惯性思维所致?

不过通过上面这篇文章,cnlyl(海龙王)的正则功底和钻研精神大家已经有目共睹了。高手,javascript版需要你,csdn需要你!

cnlyl 2003-06-04
  • 打赏
  • 举报
回复
哈哈!我昨天给出的方法成功地避免了$10问题,不算成功吗???
问题的关键是要穷尽一切办法不让"$1"+"0$2"中的$1与其后的0结合。如果能直接应用$1、$2的值用replace(oPattern, ($1)+"0"+$2 )就行了。但令人遗憾的是在replace中$1、$2引用必须用引号,也就是字符串套字符串"$1"、"$2",象用函数等方法隔开$10$2,是行不通的。
不同厂商甚至同一厂商不同版本的浏览器,在正则表达式匹配上由于bug或实现上是不同的,"想要一个规范的通用的没有歧义的正则",我认为是不可能。
跟if ( ns )、if ( IE )方法一样。我昨天给出的方法已经算是通用的了:写一个函数,分几种情况,为几个不同版本浏览器定义Express,然后,replace(oPattern, Express ),没有什么不好啊?
昨天,我也试过用RegExp.$1、RegExp.$2,可以直接引用,不存在字符串套字符串的问题,不过它是最后匹配结果,因此,昨天我放弃了。今天,我又拾起这个想法:在我们的问题中,字符串的定界符如果相同,如本例的/,那么我们可以使用RegExp.$1:

var s = "01/1/2/3/4/04/5";
s = s.replace(/(^|\D)0*(\d)/g, RegExp.$1+"0$2");
status = s;

Netscape 4.77得到了希望的结果:/01/01/02... RegExp.$1使用的是当前正则(\D)最后匹配结果(验证:如果s="01/1/2/3/4/04~5";结果为:~01~01~02...);
而那游戏机厂商的IE,运行的到的结果是:010102... RegExp.$1用的是空串,实际它是引用上次正则函数(包括其他函数)匹配的结果,即,RegExp.$1值不确定。验证:将程序重复两边得到希望的结果:

// IE:

var s = "01/1/2/3/4/04/5";
s = s.replace(/(^|\D)0*(\d)/g, RegExp.$1+"0$2");
var s = "01/1/2/3/4/04/5";
s = s.replace(/(^|\D)0*(\d)/g, RegExp.$1+"0$2");
status = s;

既然RegExp.$1问题基本弄清楚了,通用的方法也就有了:

//Netscape 4.77 && IE

var s = "01/1/2/3/4/04/5";
s.match ( /(\D)/ ); // 特别为Xbox厂商的IE RegExp.$1取得第一个定界符
s = s.replace(/(^|\D)0*(\d)/g, RegExp.$1+"0$2");
status = s;

但,这个方法有它的局限性:
1.如果源s的第一个字符不是定界符,将多一个定界符。如果这不是你所希望的,可以在函数中用return(s.substr(1,s.length-1));返回你希望的结果;
2.使用的是第一个定界符, 如s="1/1A2B3C4D04~5"; 返回:/01/01/02/03/04/05。如果你确保源字符串中的定界符都一样或这种结果就是你所希望的,上面的方法应该是比较通用的。

从Netscape 4.77不支持正则预查和RegExp.$1等问题上,emu (ston)想要的"想要的是一个规范的通用的没有歧义的正则",窃以为简直是想要海市蜃楼,无异于想让公鸡下蛋,母鸡打鸣!呵呵....

注意:上面的RegExp.$1、RegExp.$2...的说明只是针对replace()方法,我想在match()、exec()、test()等方法调用后,RegExp.$1、RegExp.$2应该与参考手册相同...

至于昨天cExpress = ( document.all ? "$10$2" : "$1$9999999999" + "0$2" )的写法,昨天写帖子时我想到了。只是为了突出$9999999,区分$99999999990。

本龙王最擅长构造简单、晦涩难懂的表达式和行数少的程序,构造正则更是如此,我写的东西被别人称为具有"只写"属性,没有"读"属性。
这个问题我不再发帖子了!
我用javascript没几天,单位的一个任务(正则是我使用unix、linux熟悉的)。有些问题还要请教,希望大家帮忙!
emu 2003-06-03
  • 打赏
  • 举报
回复
原来ns7已经修正了这个bug。

cnlyl 2003-06-03
  • 打赏
  • 举报
回复
等我在找个低版本的在Windows下琢磨琢磨。
cnlyl 2003-06-03
  • 打赏
  • 举报
回复
我用的是Netscape7.0,通过!
emu 2003-06-03
  • 打赏
  • 举报
回复
cnlyl(海龙王) :

在ns上和fason(【阿信(你是我的温柔)】) 的结果一样。因为"$1"+"0$2"会先被计算,得出结果“$10$2”之后才被当参数传给replace,所以在ns6下面不通过。
cnlyl 2003-06-03
  • 打赏
  • 举报
回复
我已经在我单位linux服务器上的Netscape通过验证,这用不着怀疑。但Winodws下我没安装Netscape,没验证,估计不应出现问题。
funboy88 2003-06-03
  • 打赏
  • 举报
回复
s="1/01/2/3/4/04/5";
s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1"+"0$2");
这个能用嘛?
这个可能不行吧
dreamfly8848 2003-06-02
  • 打赏
  • 举报
回复
wo lai ding yi xia
emu 2003-06-02
  • 打赏
  • 举报
回复
哈哈,漂亮
Javcy 2003-06-02
  • 打赏
  • 举报
回复
study!
cnlyl 2003-06-02
  • 打赏
  • 举报
回复
简单,小菜一碟(你们想得太复杂了):
s="1/01/2/3/4/04/5";
s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1"+"0$2");
emu 2003-05-31
  • 打赏
  • 举报
回复
up
blestcc 2003-05-31
  • 打赏
  • 举报
回复
关注
emu 2003-05-26
  • 打赏
  • 举报
回复
噢,也不成:

<SCRIPT LANGUAGE="JavaScript">
<!--
s="a1/b1/c2/d3/e4f/4g/h5";
s = s.replace(/(^|\D)(\d)(?=\D|$)/g,"$1~$2").replace(/~/g,"0");
alert(s);
s="a1/b1/c2/d3/e4f/4g/h5";
var reg=/\b(\d)\b/g;
s=s.replace(reg,"0$1");
alert(s);
//-->
</SCRIPT>

其实单词分界在这里实现的功能和我要求的“用一个正则将一个串中的单一个的数字改为两位的0?格式”并不相符。我需要的是“数字分界”。
加载更多回复(18)

87,907

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧