`
aerchi
  • 浏览: 422219 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
文章分类
社区版块
存档分类
最新评论

JAVA 正则表达式

 
阅读更多

// 反斜杠
/t 间隔 ('/u0009')
/n 换行 ('/u000A')
/r 回车 ('/u000D')
/d 数字 等价于[0-9]
/D 非数字 等价于[^0-9]
/s 空白符号 [/t/n/x0B/f/r]
/S 非空白符号 [^/t/n/x0B/f/r]
/w 单独字符 [a-zA-Z_0-9]
/W 非单独字符 [^a-zA-Z_0-9]
/f 换页符
/e Escape
/b 一个单词的边界
/B 一个非单词的边界
/G 前一个匹配的结束

^为限制开头
^java 条件限制为以Java为开头字符
$为限制结尾
java$ 条件限制为以java为结尾字符
. 条件限制除/n以外任意一个单独字符
java.. 条件限制为java后除换行外任意两个字符


加入特定限制条件「[]」
[a-z] 条件限制在小写a to z范围中一个字符
[A-Z] 条件限制在大写A to Z范围中一个字符
[a-zA-Z] 条件限制在小写a to z或大写A to Z范围中一个字符
[0-9] 条件限制在小写0 to 9范围中一个字符
[0-9a-z] 条件限制在小写0 to 9或a to z范围中一个字符
[0-9[a-z]] 条件限制在小写0 to 9或a to z范围中一个字符(交集)

[]中加入^后加再次限制条件「[^]」
[^a-z] 条件限制在非小写a to z范围中一个字符
[^A-Z] 条件限制在非大写A to Z范围中一个字符
[^a-zA-Z] 条件限制在非小写a to z或大写A to Z范围中一个字符
[^0-9] 条件限制在非小写0 to 9范围中一个字符
[^0-9a-z] 条件限制在非小写0 to 9或a to z范围中一个字符
[^0-9[a-z]] 条件限制在非小写0 to 9或a to z范围中一个字符(交集)

在限制条件为特定字符出现0次以上时,可以使用「*」
J* 0个以上J
.* 0个以上任意字符
J.*D J与D之间0个以上任意字符

在限制条件为特定字符出现1次以上时,可以使用「+」
J+ 1个以上J
.+ 1个以上任意字符
J.+D J与D之间1个以上任意字符

在限制条件为特定字符出现有0或1次以上时,可以使用「?」
JA? J或者JA出现

限制为连续出现指定次数字符「{a}」
J{2} JJ
J{3} JJJ
文字a个以上,并且「{a,}」
J{3,} JJJ,JJJJ,JJJJJ,???(3次以上J并存)
文字个以上,b个以下「{a,b}」
J{3,5} JJJ或JJJJ或JJJJJ
两者取一「|」
J|A J或A
Java|Hello Java或Hello

「()」中规定一个组合类型
比如,我查询<a href=/"index.html/">index</a>中<a href></a>间的数据,可写作<a.*href=/".*/">(.+?)</a>

在使用Pattern.compile函数时,可以加入控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex, int flag)

flag的取值范围如下:
Pattern.CANON_EQ 当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配"?"。默认情况下,不考虑"规 范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹 配,只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS(?x) 在这种模式下,匹配时会忽略(正则表达式里的)空格字符(译者注:不是指表达式里的"//s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL(?s) 在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式'.'不匹配行的结束符。
Pattern.MULTILINE
(?m) 在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE
(?u) 在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES(?d) 在这个模式下,只有'/n'才被认作一行的中止,并且与'.','^',以及'$'进行匹配。




这个就是一个正则表达式,b,w,*都是正则表达式的meta character原字符,
\b表示单词的边界,w表示任意的可构成单词的字母数字,*表示前面的字母(当然可以
是更复杂的组之类的了东东)重复0次或0次以上,a当然还是a了。所以这个regex就
匹配单词开头为a的单词了。
二、下面总结一下基本的正则表达式的meta character以及它们含义:
. 匹配任意一个字符 $ 匹配一行的结尾 ^ 匹配一行的开头(在[]里面表示否定)
{} 定义了一个范围  [] 定义了一个字符类 () 定义了一个组
*前面出现0次以上 + 前面匹配一次以上 ?前面出现0次或一次  
\ 后面的字符不会看作metacharacter \w 字母数字下划线 \W 非字母数字下划线
\d 单个数字 \D单个非数字 | 或,二者之一 &&与操作符 \b单词边界
下面看看几个简单的例子:
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
三、java.util.regex提供的操作接口:
java.util.regex包提供了操作正则表达式的模型,整个模型优雅而简洁,只有三个类:Pattern、Matcher和
PatternSyntaxException。下面将要总结他们提供的方法,以及如何灵活应用来处理文本。












^ The caret (^) tells the regular expression that the character must not match the characters to follow.
比如要匹配所有除了a或b的字符,字符类可以这么写[^ab]
^ 定位符规定匹配模式必须出现在目标字符串的开头
那是否说^在[ ]里面就 表示排除(负向类), 在[ ]前面就表示要在开头?
$ 定位符规定匹配模式必须出现在目标对象的结尾

- 范围类,如要匹配a到z的所有字母,字符类可以这么写[a-z]

{n} 出现多少次

/^[0-9]{7}$/ 匹配的就是一个仅包含7个数字的字符串


7.1 RegExp 对象可以有一个或两个参数.
var reCat = newRegExp("cat")//这个表达式只会匹配字符串中出现的第一个"cat"
var reCat = newRegExp("cat","g")//匹配所有出现的"cat"

正则表达式字面量
var reCat =/cat/gi; 注意字面量不需 要放在引号里

判断某个字符串是否匹配指定的模式
RegExp.test(str) 如果给定的字符串匹配这个模式,返回true,否则返回false.reCat.test("cat")//返回true

RegExp.exec(str) 返回一个数组,数组中第一个元素是匹配字符串,其他是反向引用. 如果没有找到匹配,返回null
返回的数组有一个index属性,这个属性的值 是匹配字符串中第一个字符在原字符串中的下标
var toMarch6 = "1 3";
var regExp6 = /(\d+)\s*(\d+)/;
var result = regExp6.exec(toMarch6);
dwr(result);//1 3,1,3
dwr(RegExp.$1 +" "+RegExp.$2);//1 3
当正则表达式加上了参数g,这个正则表达式会从正则表达式对象的lastIndex属 性指定的位置开始查找,如果找到一个匹配,
会将lastIndex属性设置为匹配字符串后面 一个位置的下标.
var toMarch7 = "1 3 4 5";
var regExp7 = /(\d+)\s*(\d+)/g;
var result7
while((result7= regExp7.exec(toMarch7)) !=null){
dwr(result7);//分别为1 3,1,3 和 4 5,4,5
dwr(regExp7.lastIndex);//分别为3和7
}
String.match(reCat) 返回一个包含在字符串中的所有匹配数组
var toMatch = "a bat, a cat, a fAt baT, a faT cat";
var reAt = /at/gi;//如果不加参数g,返回的数组只会包含一个匹配元素
var arrMatchs = toMatch.match(reAt);
返回一个数组["at","at","At","aT","aT","at"]

String.search(reCat)indexOf类似,返回在字符串中出现的第一个匹配的位置,全局匹配表达式g在这里不起作 用toMatch.search(reAt);//输出3

String.replace(matchStr, replaceStr)
用第二个参数替换某个子串(第一个 参数)的所有匹配.第一个参数既可以是匹配的字符串,也可以是用于匹配的一个正则表达式,
返回是替换后的整个字符串
var sToChange = "The sky is red";
var reRed = /red/;
sToChange.replace(reRed,"blue"); //输出The sky is blue

String.split(reCat) 将字符串分割成子串,作为数组返回
var sColor = "red, blue, yellow";
var reExp = /\,/;
var arrs = sColor.split(reExp); //得到一个数组["red","blue","yellow"] 注意逗号在正则表达式有
特殊含义,这边需要转义

7.2 简单模式(元字符,字符类,量词)
元字符 11个()[] {} \ ^ $ | ? * + . 要匹配字符串中的元字符,需要转义/\^/
注意var reMark = new RegExp("\\^");当正则表达式以非字面量的形式表示时,所有的反斜杠"\"都要用两个反斜杠"\\"来替换.
因为javascript字符串解析器会按照翻译\n的 方式尝试翻译\?.为了保证不会出现这个问题,在元字符的前面加上两个反斜杠,
我们称之为双重转义.(不太懂这个解释,我的理解是\本身也是元字符,先要对它转义得到"\",然后再用这个"\"对接下来的元字符转义)

预定义的特殊字符

\t

制表符

\n

换行符

\r

回车符

\f

换页符

\a

Alert字符

\e

Escape字符

\cX

与X相应 的控制字符

\b

回退字符

\v

垂直制表符

\o

空字符




字符类
将一些字符放入方括号中.

1, 简单类
var toMatch = "a bat, a cat, a fAt baT, a faT cat";
var reg =/[bcf]at/gi;
var arrs = toMatch.match(reg); 返回的数组[“bat”, “Cat”, “fAt”, “baT”, “faT”, “cat”]

2,负向类可 以指定要排除的字符,^要在[ ]里面
匹配除了ab以外的所有字符,那么这个字符类为[^ab]. 脱字符^告诉正则表达式字符不能匹配后面跟着的字符
只想获得包含at但不能以b或c开头的字符,/[^bc]at/gi

3, 范围类
[a-z]
匹配所有小写字母
结合负向类可以排除给定范围内的所有字符, 例如要排除字符1~4,可以使用类[^1-4]

4, 组合类
[a-z1-9\n]

5, 预定义类

代码等同于匹配
.[^\n\r] 除了换行回车意外的任意字符
\d[0-9] 数字
\D[^0-9] 非数字
\s[ \t\n\r\x0B\f] 空白字符
\S[^ \t\n\r\x0B\f] 非空白字符
\w[a-zA-Z_0-9] 单词字符(所有字母,数字和下划线)
\W[^a-zA-Z_0-9] 非单词字符


6, 量词
用于指定某个特定模式出现的次数
? 出现0次或1次
* 出现0次或多次(任意次)
+ 出现1次或多次(至少出现一次)
{n} 一定出现n次
{n,m} 至少出现n次但不超过m次
{n,} 至少出现n次

贪婪的,惰性的,支配性的量词
贪婪量 词先看整个字符串是否匹配,如果没有发现匹配,它去掉该字符串中最后一个字符,并再次尝试.重复这个过程直到发现匹配 或者字符串不剩任何字符.
结合 下面会见到的两个例子, 实际过程可能是这样的:
第一步按上面的描述执行, 如果字符串不剩任何字符还是没有找到一个匹配, 那么删除字符串的第一个字符, 重复第一步.
惰性量词先看字符串中第一个字符是否匹配.如果单独这个 字符还不够,就读入下一个字符,组成两个字符的字符串.如果还是没有发现匹配,惰性量词继续从
字符串中添加字符直到发现匹配或者整个字符串都检查过也没有匹配.与贪婪量词的工作方式正好相反.
支配量词只尝试匹配整个字符串.如果整个字符串不能产生匹配,不 做进一步尝试.(IE不支持,Mozilla把支配量词当做贪婪的)

贪婪惰性支配描述
????+ 零次或一次出现
**?*+ 零次或多次出现
++?++ 一次或多次出现
{n}{n}? {n}+ 恰好n次出现
{n,m}{n,m}?{n,m}+ 至少n次之多m次出现
{n,}{n,}?{n,}+ 至少n次出现


7.3 复杂模式
1, 分组

分组是通过一系 列括号包围一系列字符,字符类以及量词来使用的.
/(dog){2}/g 匹配dogdog
/{[bd]ad?}*/ 匹配ba, da, bad, dad等
去掉开头结尾的空白字符
String.prototype.trim = function(){
//注意, 分组里面.*?一定要是惰性的,不然这 个分组会把最后的空白字符也匹配进去
var reExtraStr =/^\s+(.*?)\s+$/;
return this.replace(reExtraStr,"$1");
}

2, 反向引用
在 表达式计算完成之后,每个分组都被存放在一个特殊的地方以备将来使用.这些存储在分组中的特殊值,我们称之为反向引用(backreference).
反向引用是按照从左到右遇到的左括号字符的顺序进行创建和编号的.

反向引用的几种不同使用方法:
* 使用正则表达式对象的test(), exec()方法后,反向引用的值可以从RegExp对象的构造函数中获得
var toMarch = "#12345";
var regExp = /#(\d*)/;
regExp.exec(toMarch);
dwr(RegExp.$1);
* 还可以直接在定义分组的表达式中包含反向引用,这可以通过使用特 殊转义序列如\1,\2等实现.
var toMarch2 = "dogdog";
var regExp2 = /(dog)\1/;
dwr(regExp2.test(toMarch2));
* 反向引用可以用在String对象的replace()方法中
var toMarch3 = "123123123 3211231231";
var regExp3 = /(\d+)\s*(\d+)/;
var sNew = toMarch3.replace(regExp3,"$2$1");//注意replace不改变原来的字符串,而是返回一个替换后的新 字符串
dwr(sNew);

3, 候选
用一个管道符(|),它放在两个单独的模式之间.
var toMarch4 = "dog";
var toMarch5 = "cat";
var regExp4 = /dog|cat/;
dwr(regExp4.test(toMarch4));//true
dwr(regExp4.test(toMarch5));//true

OR模式的一种通常用法是从用户输入中删除不合适的单词.
var userInput = "badWord1asdasdandBadWord2";
var toMarch6 = /badword1|badword2/gi;
var newStr = userInput.replace(toMarch6, function(march){
return march.replace(/./g,"*");
});
dwr(newStr);//********asdasdand********

string.replace(regexp, replacement)
replacement既 可以是一个替换的字符串,也可以是一个function
如果是function的情况, 这个function会为每一个匹配执行一次,这 个function的返回值作为最终替换的字符串.
传给function的第一个参数是 第一个匹配的字符串;
第二个参数是匹配字符串在原始字符串中的位置;
第三个参数是原始字符串本身.

4, 非捕获性分组
创建反向引用的分组称为捕获性分组, 非捕获性分组不会创建反向引用.
在较长的正则表达式中存储反向引用会降低匹 配的速度.
要创建非捕获性分组,只要在左括号后面紧跟一个问 号和冒号.
var str = "#123456";
var regE = /#(?:123456)/;
regE.test(str);
dwr(RegExp.$1);//""

//去除所有的HTML标签
String.prototype.skipHTML = function(){
var regExp =/<(?:.|\s)*?>/g;
return this.replace(regExp,"");
}

5, 前瞻
表示当某个特定的字符分组出现在另一个字符串之前时才去捕获它.
前瞻分正向前瞻负向前瞻, 正向前瞻检查的是接下来出现的是不是某个特定的字符集. 而负向前瞻则是检查接下来的不应该出现的特定字符集.
正向前瞻需要将模式放在(?=和)之间,注意这不是分组,虽然它也用到 括号. 负向前瞻需要将模式放在(!=和)之间.
var toMarch1 = "bedroom";
var toMarch2 = "bedding";
var bedReg = /(bed(?=room))/;
dwr(bedReg.test(toMarch1));//true
dwr(bedReg.exec(toMarch1));//bed,bed 因此这个正则表达式返回的第一个匹配是bed,而不是bedroom,但是它只会去匹配后面跟着 room的bed,有点搞
dwr(RegExp.$1);//bed
dwr(bedReg.test(toMarch2));//false

6, 边界
边界用于正则表达式中表示模式的位置.
^ 行开头
$ 行结尾
\b 单词的边界
\B 非单词的边界

查找一个出现在行尾的单词:
var toMarch3 = "Important word is the last one.";
var regExp3 =/(\w+)\.$/;//这边结合上面对贪婪量词的解释,有点不明白为何能匹配one?.
regExp3.test(toMarch3);
dwr(RegExp.$1);//one

查找一个出现在行首的单词:
var toMarch4 = "Important word is the last one.";
var regExp4 =/^(\w+)/;//或者var regExp4 = /^(.+?)\b/;
regExp4.test(toMarch4);
dwr(RegExp.$1);

抽取出所有的单词
var toMarch5 = "First Second Third Fourth Fifth Sixth";
var regExp5 =/\b(\S+?)\b/g;//或者 /\b(\S+)\b/g 和 /(\w+)/g
var sArr = toMarch5.match(regExp5);
dwr(sArr);//First Second Third Fourth Fifth Sixth
注意这边如果用/(\w+?)/g是不行的,这样得到的是一个一个的字母F,i,r,s,t,S...

==========================================================================================
与上面疑问类似的一个问题
例子代码,如下:
str = "abbb1234abbbaabbbaaabbb1234";
re = /.*bbb/g;
alert(str.match(re)); //结果为abbb1234abbbaabbbaaabbb
re = /.*?bbb/g;
alert(str.match(re)); //结果为abbb,1234abbb,aabbb,aaabbb
re = /a*bbb/g;
alert(str.match(re)); //结果为abbb,abbb,aabbb,aaabbb
re = /a*?bbb/g;
alert(str.match(re)); //结果为abbb,abbb,aabbb,aaabbb

对于第一、第二和第四个打印结果容易理解:
第一个str.match(re),贪婪量词先匹配整个字串,若不匹配去掉一个尾字 符,继续匹配;
第二个str.match(re),惰性量词从第一个字符开始递加去匹配,直到匹配成功,清空字串,从下一个 字符继续匹配。
第四个str.match(re),同第二个。

但第三个就不知道如何解释,如果按照第一个的方式去理解:
先 匹配整个字串,发现不匹配,去掉尾字符,继续匹配...到最后,结果应该是abbb;
而其结果却为abbb,abbb,aabbb,aaabbb

以下为论坛解释
对于第三个正则,就是这样来执行的;
首 先清楚了是用了简单量词(*),而我们知道了*是贪婪量词:
贪婪量词执行过程。正好楼主所说的那样。“先匹配整体,若不匹配则去掉尾字 符继续匹配,直到成功或者结束”
这样说应说只能得到第一被匹配的对象。
javascript 中的match返回的是所有匹配。
对于要返回所有匹配。
它还有第二个步:就是匹配成功后,从最近的一个匹配后的下一个字符开始重新贪婪模式匹配。重新执行它的步骤;
例:
str = "abbb1234abbbaabbbaaabbb1234";
re = /a*bbb/g;
alert(str.match(re));

它的执行过程:
第一步:首先整个字符串("abbb1234abbbaabbbaaabbb1234")匹配,发现匹配不成 功,
接着。删除最后一个字符("4"),成了("abbb1234abbbaabbbaaabbb123"),这样依次执行 下去;
执行...最后, 发现("abbb")可以被匹配了..所以生成第一个匹配值。

但在这个match方法中是返回所有匹配。所以..
第二步:从最近的一个匹配(这里就是第一次匹配了)后的下一个字符开始重新贪婪模式 匹配.得到字符串是
("1234abbbaabbbaaabbb1234"),然后。就按第一步执行。。

执行完第一步 后。
然后就从最近一次(这里就是第二次匹配了)

....后面的过程就是重复一二步了。。

但第二步时若继续按正则/a*bbb/g去匹配“1234abbbaabbbaaabbb1234” 的话,应该是匹配不到才对吧?
---------------------------------------------------
怎么匹配不到呢。。
正 则表达式执行的时候。首先得找到前导字符(a), a是一个普通字符。普通字符,搜索的顺序为从左到右。。
所以搜索 “1234abbbaabbbaaabbb1234”字符串时,
得先匹配出a字符来"abbbaabbbaaabbb1234”,
而 解析器又发现了a后面是一个贪婪字符。就按贪婪模式去匹配(从右到左)

注意:/a*bbb/g 用到了全局匹配, 以上分析的症结所在可能就是因为一个"g"
==========================================================================================

7, 多行模式
一下代码中的正则表达式想要匹配行末的一个单词.它只会匹配最后的Sixth, 但实际上这个字符串包含两个换行符,因此, Second, Fourth也应该匹配出来,因此引入了多行模式
var toMarch6 = "First Second\nThird Fourth\nFifth Sixth";
var regExp6 =/(\w+)$/g;
var sArr6 = toMarch6.match(regExp6);
dwr(sArr6);
要 引入多行模式,需要在正则表达式后面添加m选项, 这会让$边界匹配换行符(\n) 和字符串真正的结尾.
var regExp6 =/(\w+)$/gm;

判 断日期的正则表达式:
function isValidDate(s){
var reDate = /(?:[1-9]|0[1-9]|[12][0-9]|3[01])\/(?:[1-9]|0[1-9]|1[0-2])\/(?:19\d{2}|20\d{2})/;
return reDate.test(s);
}



--
Best Regards
RicoYu


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics