正则表达式的环视实际应用案例
作者:互联网
一、千位分隔符案例(一)
逆序环视和顺序环视结合应用。
**需求:**数字格式化成用 ,
分隔的货币格式。
正则表达式:(?n)(?<=\d)(?<!\.\d*)(?=(\d{3})+(\.|$))
测试代码:
double[] data = new double[] {
0, 12, 123, 1234, 12345, 123456, 1234567, 123456789, 1234567890, 12.345,
123.456, 1234.56, 12345.6789, 123456.789, 1234567.89, 12345678.9
};
foreach (double d in data) {
richTextBox2.Text += "源字符串:" + d.ToString().PadRight(15) + "格式化:"
+ Regex.Replace(d.ToString(), @"(?n)(?<=\d)(?<!\.\d*)(?=(\d{3})+(\.|$))", ",") + "\n";
}
输出结果:
源字符串:0 格式化:0
源字符串:12 格式化:12
源字符串:123 格式化:123
源字符串:1234 格式化:1,234
源字符串:12345 格式化:12,345
源字符串:123456 格式化:123,456
源字符串:1234567 格式化:1,234,567
源字符串:123456789 格式化:123,456,789
源字符串:1234567890 格式化:1,234,567,890
源字符串:12.345 格式化:12.345
源字符串:123.456 格式化:123.456
源字符串:1234.56 格式化:1,234.56
源字符串:12345.6789 格式化:12,345.6789
源字符串:123456.789 格式化:123,456.789
源字符串:1234567.89 格式化:1,234,567.89
源字符串:12345678.9 格式化:12,345,678.9
实现分析:
首先根据需求可以确定是把一些特定的位置替换为 ,
,接下来就是分析并找到这些位置的规律,并抽象出来以正则表达式来表示。
-
这个位置的左侧必须为数字
-
这个位置右侧到出现
.
或结尾为止,必须是数字,且数字的个数必须为 3 的倍数 -
这个位置左侧相隔任意个数字不能出现
.
由以上三条,就可以完全确定这些位置,只要实现以上三条,组合一下正则表达式就可以了。
根据分析,最终匹配的结果是一个位置,所以所有子表达式都要求是零宽度。
-
是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求必须出现,所以是肯定的,符合这一条件的子表达式即为
(?<=\d)
-
是对当前所在位置右侧附加的条件,所以要用到顺序环视,也是要求出现,所以是肯定的,是数字,且个数为3的倍数,即
(?=(\d{3})+)
,到出现.
或结尾为止,即(?=(\d{3})+(\.|$))
-
是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求不能出现,所以是否定的,即
(?<!\.\d*)
因为零宽度的子表达式是非互斥的,最后匹配的都是同一个位置,所以先后顺序是不影响最后的匹配结果的,可以任意组合,只是习惯上把逆序环视写在左侧,顺序环视写在右侧。
说明:这里只是为了说明环视的使用而举的一个例子,实际上这个需求直接用 string.Format 就可以做到。
二、千位分隔符案例(二)
千位分隔符,顾名思义,就是数字每隔三位添加一个逗号。这是参考西方的习惯,在数字之中加入一个符号,避免因数字太长难以直观的看出它的值。
那么怎么将一串数字转化为千位分隔符形式呢?
var str = "1234567890.9876";
console.log((+str).toLocaleString()); // 1,234,567,890.988
如上,toLocaleString() 返回当前对象的“本地化”字符串形式。
- 如果该对象是 Number 类型,那么将返回该数值的按照特定符号分割的字符串形式;
- 如果该对象是 Array 类型,那么先将数组中的每项转化为字符串,然后将这些字符串以指定分隔符连接起来并返回。
我们尝试使用环视来处理下:
var str = 1234567890;
function thousand(str){
return str.replace(/(?!^)(?=([0-9]{3})+$)/g,','); // 进行了好多次迭代匹配,匹配到 3 个位置,把匹配到的位置替换成逗号
}
console.log(thousand(str));//"1,234,567,890"
console.log(thousand("123456"));//"123,456"
console.log(thousand("1234567879876543210"));//"1,234,567,879,876,543,210"
上述使用到的正则表达式分为两块 (?!^) 和 (?=([0-9]{3})+$)。我们先来看后面的部分,然后逐步分析之。
[0-9]{3}
表示连续3位数字;([0-9]{3})+
表示连续3位数字至少出现一次或更多次;([0-9]{3})+$
直到字符串末尾;- 那么
(?=([0-9]{3})+$)
就表示匹配一个零宽度的位置,并且从这个位置到字符串末尾,中间拥有至少 1 组以3个数字为 1 组的数字(即 3 的正整数倍得到数值为数字的个数;就是 3 乘以 1,3 乘以 2,以此得到的乘积为个数的数字); - 正则表达式使用全局匹配
g
,表示匹配到一个位置后,它会继续匹配,直至匹配不到; - 将这个位置替换为逗号,实际上就是每 3 位数字添加一个逗号;
- 当然对于字符串
123456
这种刚好拥有 3 的正整数倍个数的数字,当然不能在1前面添加逗号,那么使用(?!^)
就指定了这个替换的位置不能为起始位置。
三、顺序肯定环视
假如现在,js 通过 ajax 获取到一段 html 代码如下:
var responseText = "<div data='dev.xxx.txt'></div><img src='dev.xxx.png'/>";
现我们需要替换 img 标签的 src 属性中的 dev
字符串为 test
字符串。
-
由于上述 responseText 字符串中包含至少两个子字符串
dev
,显然不能直接 replace 字符串dev
为test
; -
同时由于 js 中不支持逆序环视,我们也不能在正则中判断前缀为
src='
,然后再替换dev
; -
我们注意到 img 标签的 src 属性以
.png
结尾,基于此,就可以使用顺序肯定环视。
var reg = /dev(?=[^']*png)/; //为了防止匹配到第一个dev, 通配符前面需要排除单引号或者是尖括号
var str = responseText.replace(reg,"test");
console.log(str);//<div data='dev.xxx'></div><img src='test.xxx.png' />
当然,以上不止顺序肯定环视一种解法,捕获性分组同样可以做到。那么环视高级在哪里呢?环视高级的地方就在于它通过一次捕获就可以定位到一个位置,对于复杂的文本替换场景常有奇效,而分组则需要更多的操作。
标签:格式化,数字,正则表达式,环视,位置,案例,str,字符串 来源: https://blog.csdn.net/liaowenxiong/article/details/118462746