“ /b ”匹配单词边界,不匹配任何字符。
“ /b ”匹配的只是一个位置,这个位置的一侧是构成单词的字符,另一侧为非单词字符、字符串的开始或结束位置。“ /b ”是零宽度的。
基本上所有的资料里都会说“ /b ”是单词边界,但是关于 “ 单词 ” 的范围却是少有提及。通常情况下,正则表达式中所谓的 “ 单词 ” ,就是由“ /w ”所定义的字符所组成的子串。
“ /b ”表示所在位置的一侧为单词字符,另一侧为非单词字符、字符串的开始或结束位置,也就相当于
(?<!/w)(?=/w)|(?<=/w)(?!/w)
思考: 以下写法为什么不等价于“ /b ”
(?<=/W)(?=/w)|(?<=/w)(?=/W)
即然涉及到“ /w ”,那就要先考察一下它的范围。
在支持 ASCII 码的语言中,如 JavaScript ,“ /w ”等价于 [a-zA-Z0-9_] ;
在支持 Unicode 的语言中,如 .NET ,默认情况下,“ /w ”除可以匹配 [a-zA-Z0-9_] 外,还可以匹配一些 Unicode 字符集,如汉字,全角数字等等。
几乎所有常见的语言都遵循这样一个规律,只有 Java 是个例外。在 Java 中,“ /w ”的表现是比较奇怪的, Java 是支持 Unicode 的,但 Java 的正则中的“ /w ”却是等价于 [a-zA-Z0-9_] 的。
先来看一下“ /w ”在几种语言中匹配的例子
JavaScript
< script language ="javascript">
var str = "abc_123 中文_d3=efg 汉字%";
var reg = //w+/g;
var arr = str.match(reg);
if(arr != null)
{
for(var i=0;i<arr.length;i++)
{
document.write(arr[i] + "<br />");
}
}
</ script >
/*-------- JavaScript 中输出 --------
abc_123
_d3
Efg
*/
C#
string test = "abc_123 中文_d3=efg 汉字%" ;
MatchCollection mc = Regex .Matches(test, @"/w+" );
foreach (Match m in mc)
{
richTextBox2.Text += m.Value + "/n" ;
}
/*-------- C# 中输出 --------
abc_123 中文_d3
efg 汉字
*/
Java
String test = "abc_123 中文_d3=efg 汉字%" ;
String reg = "//w+" ;
Matcher m = Pattern.compile(reg).matcher(test);
while (m.find())
{
System.out .println(m.group());
}
/*-------- Java 中输出 --------
abc_123
_d3
Efg
*/
可以看到,“ /w ”在 Java 中的输出和 JavaScript 中是一样的,都是只支持 ASCII 字符。
常见语言中“ /w ”的范围确定了,那么是不是可以认为“ /b ”的匹配范围与“ /w ”也是一致的呢?
再看下下面的例子:
源字符串: abc_123 中文 _d3= 汉字 efg
正则表达式: ./b.
JavaScript
< script language ="javascript">
var str = "abc_123 中文_d3=efg 汉字%";
var reg = /./b./g;
var arr = str.match(reg);
if(arr != null)
{
for(var i=0;i<arr.length;i++)
{
document.write(arr[i] + "<br />");
}
}
</ script >
/*-------- JavaScript 中输出 --------
3 中
文_
3=
g 汉
*/
C#
string test = "abc_123 中文_d3=efg 汉字%" ;
MatchCollection mc = Regex .Matches(test, @"./b." );
foreach (Match m in mc)
{
richTextBox2.Text += m.Value + "/n" ;
}
/*-------- C# 中输出 --------
3=
字%
*/
Java
String test = "abc_123 中文_d3=efg 汉字%" ;
String reg = ".//b." ;
Matcher m = Pattern.compile(reg).matcher(test);
while (m.find())
{
System.out .println(m.group());
}
/*-------- Java 中输出 --------
3=
字%
*/
可以看到, Java 的输出和 .NET 是一致的,“ /b ”在 Java 中是支持 Unicode 的。
所以总的来说, Java 中的“ /w ”是很奇怪的,而“ /b ”是与其它语言表现一致的,在使用时需要注意。
“ /b ”一般应用在需要匹配某一单词字符组成的子串,但这一字符不能包含在同样由单词字符组成的更长的子串中。
比如要替换掉一段英文中的单词“ to ”,而“ today ”显然不在替换的范围内,所以正则可以用“ /bto/b ”来限定。
用得比较多的场景是在 HTML 标签的匹配中,用以区分相互包含的标签,比如要过滤掉 <b> 、 </b> 、 <p…> 、 <img…> 等标签,但要保留 <br /> 标签,正则可以写成“ <(/?b|p|img)/b[^>]*> ”。
举例:统计以“ , ”分割的元素中“ 3 ”的个数
string test = "137,1,33,4,3,6,21,3,35,93,2,98" ;
int count = Regex .Matches(test, @"/b3/b" ).Count; // 结果:2
稍复杂一些的应用通常都是与其它一些正则语法规则一起使用的,参考一个帖子 求一正则表达式
“ /b ”用在正则中,通常情况下都是表示单词边界的,只有在字符组中,它表示的是退格键,即
[a-z/b]
此处的“ /b ”表示的是退格键,而不是单词边界。