抬头仰望星空,是否能发现自己的渺小。

伪斜杠青年

人们总是混淆了欲望和理想

来一波,隐藏至深的正则表达式

最近写了好几个关于正则的例子,第一个是过滤WordPress的数据库文章中的图片链接,另一个是写一个app时候要判断一个表达式是否符合逻辑,是时候把这些积累的东西给堆出来了,毕竟,谁都记不了那么清楚啊!!!

第一篇博文内容:特例解释(请关注其用法,而不是示例用的什么语言,Perl,java?随他呢)

(1) 点号(.),它用来匹配任意一个单字符(\n 排除在外,后面我默认不再提这个例外)。

所以: "twoon" =~ /tw.on/ 为 true
 “twvon" =~ /tw.on/ 也为 true.

        点号在正则表达式中是有特殊含义的,有时我们可能也要匹配点号,这时就需要转义一下。

"twoo.n" =~ /twoo\.n/ 为true.

        正则表达中,所有其它的通配符也都可以用同样的方式进行转义,表示直接匹配通配符,去除它的特殊含义。

        你可以看到\也是一个通配符,如果要匹配它也是同样的道理。

"two\\on" =~ /two\\on/ 为true.

(2) 星号(*) : 星号代表匹配它前面一个字符任意遍(0或任意次),它是一数量词(quantifier),必须跟在其它字符的后面,否则这个表达式不正确。如:

”twoon" =~ /two*n/ 为true
“twn" =~ /two*n/ 也为true.
"twoon" =~ /*twoon/ 表达式不正确,*必须跟在其它符号后面.

       同时星号也可以匹配点号(.),点号代表任意非回车字符,因此, (.*)就代表任意字符任意次。这是一个惯常的用法,如:

/twoon.*walks/ 能匹配任意包含"twoon"在前,"walks“在后的字符串。

 所以(.*)也被称为:any old junk. 匹配任何东西。 

(3) 加号(+): 加号是一个与星号(*)类似的通配符,它也是数量词,表示匹配前面的字符一次或多次(至少一次).

       它与星号的差别就在这里,星号可以匹配0次,加号则必须一次以上。  如:

"twoon" =~ /two+n/ 为true.
"twn" =~ /two+n/ 为false.

(4) 问号(?): 问号也是一个数量词,它代表匹配前一个字符0或1次。如:

"twoon" =~ /twoo?n/ 为true
"twoon” =~ /two?n/ 为false.
"twn" =~ /two?n/ 为true.

(5) 括号(()): 括号用来表示一个组合,前面我说数量词作用在前一个字符上,这个说法事实上不准确,应该说是作用在一个组合上,一个字符是一个组合,但多个字符也可以成为组合。括号就是用来表示一个组合,被括号括起来的就是一个组合。如:

"twoon" =~ /tw(o)*n/ 为true.
"twoon" =~ /tw(oo)*n/ 为true
"twowon" =~ /t(wo)*n/ 为true.
"twoon" =~ /t(wv)*oon/ 为false.
“twoon" =~ /t(wo)+on/ 为true.
“twon" =~ /t(wo)+on/ 为false.

     括号里可以放置任何字符,也可以放置其它通配符,如  “aaabcc” =~ /(aa+b)?cc/

(6) 引用通配符:反斜杠加上数字是所谓引用通配符(back reference): \1 \2 \3 等,它的作用是引用前面的某个括号元组,如:  

"twoonwo" =~ /t(wo)on\1/ 为true

    乍看起来,似乎作用不明显,如上例,我们完全可以不用\1,而写成这样: /t(wo)on(wo)/

    在上面的例子里,这个质疑是可以理解的。但有时,我们的括号元组可能这样写的:  (we…) 因为点号代表任意字符,如果我们后面要作用这个元组,不用引用通配符, 我们根本无法引用,具体看例子:    

”weabceeweabc" =~ /(we...)ee\1/ 为 true。
“weabceeweabc" =~ /(we...)ee(we...)/ 为 true
”weabceewecdf" =~ /(we...)ee(we...)/ 也为 true.

    从第2,3个例子,我们可以看区别。\1 表示的是与前一个元组完全一样的匹配。而 \1,\2,\3等,则分别表示,从左往右数第几个元组。

“abcdef def abc" =~ /(...)(...) \2\1/ 为 true.

    在 perl 中,引用通配符中支持从1~9,写法上很活,你既可直接\1 \2 …\9这样来写,也可以写成 \g{1]  ,\g{2},…..\g{9}。后面一种写法相对复杂些,但有助于perl来理解你想表达的含义。因为反斜杠在程序语言中有特殊的信念,通常表达转义,perl 在遇到反斜杠时,它会去猜你想表达的什么。所以如果你写一个类似: \123这样的东西,它就不知怎么去解析,你是想表达 \1+23,引用后面跟着数字,还是,\12+3,或 \123,转义符后面跟数字是可以表示转义一个8进制数字的。因此这里产生了歧义。perl 5.10 于是引入了 \g{N}这种表述方式来表示引用通配符。N 甚至可以是负数,当是用负数是,它表示一个相对位置。表示从当前位置开始往左数,第N个元组,如:

"twooavvboonn" =~ /tw(oo)a(vv)b\{-2}(nn)/ 为true

(7) 中括号[]: 中括号用来表示一个字符集合(character set)

     字符集合,顾名思义,就是字符的集合,集合的元素放在中括号里,表示每次匹配中其中的一个,如: 

"twoon” =~ /[tw]woo/ 为 true

     有时如果这个集合有很多元素,如26个字母,数字等,一个个地写在中括号里,未免太麻烦太蠢笨,这时可以用连字符(hyphen)来表示一个范围,

如:[a-z]表示小写字母的集合,[a-zA-Z]表示大小写字母的集合。

     上面的用法用于提供范围来选择,但有时不匹配某个范围也是很常见的匹配需求,这时我们可以在集合的开头放一个脱字符 ^ (caret). 这种写法表示,匹配任何不在该集合中的字符,与上面的用法刚好相反。如:

"twoon" =~ /[^two]woon/ 为false
“ewoon" =~ /[^two]woon/ 为true

      由上面的用法,可知 ^,- 这两种符号在集合中有特殊含义,如果我们们想在集合中表示这两个字符,就也要转义一下。如:

[\^ab\-]

      有些字符集合是很常用的,如字母,数字等,perl提供了一些缩写来表示这些常用的集合,如:\d表示一个数字,等价于[0-9],这些特殊字符包括如下 :

\w -- (小写w) 表示字母或数字,等价于 [a-zA-Z0-9]
\W -- (大写W)非字母且非数字,与\w相反
\s -- (小写s)匹配一个空格字符,包括:空格,换行,回车,tab,等价于[ \n\r\t\f]
\S -- (大写S)匹配非空格字符,\s的相反
\d -- 表示10进制数字,等价于 [0-9]

(8) 大括号:{}  

   大括号的作用是指定重复前面一个字符多少遍:

{N} 重复N遍
{n,m} 重复 n~m 遍
{n,} 至少重复n遍
{,m} 至多重复m遍
示例:"twoon" =~ /two{2}n/ 为true.

(9) ^,& 这两个通配符用来表示在匹配串的头部或尾部匹配。

     一般我们写这种: “twoon” =~ /oo/ 正则表达式的时候,匹配是从”twoon”的开始一路匹配下去,如tw != oo,就继续往下匹配,但有时候我们可能只想匹配一下开头或结尾,这时^,&就派上用场了。^用于匹配字符串的开关,&用于匹配字符串的结尾。如: 

"twoon" =~ "^tw" 为true.
“twoon” =~ “oo" 为true
"twoon" =~ "^oo" 就为false.
”twoon" = "on&" 为true.
"twoon“ = ”oo&" 为false

(10) “或” 通配符:  正则表达式用竖线 | 表示或, (ab | cd) 表示匹配竖线左右的字符组之一,如果左右的字符数超过一个,它必须和括号一起使用。如:  

"twoon” =~ /t|ewoon/ 结果为true
"twoon" =~ /(tw|ee)oon/ 结果为true
"twoon" =~ /(ee|gs)oon/ 结果为false

第二篇博文:入门的符号说明(并未全部验证,复制粘贴可能有错,自行尝试,仅供参考)

// 反斜杠
/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开头,任意结尾的字符串

Pattern pattern = Pattern.compile("^Java.*"); 
Matcher matcher = pattern.matcher("Java不是人"); 
boolean b= matcher.matches(); 
//当条件满足时,将返回true,否则返回false 
System.out.println(b);

以多条件分割字符串时

Pattern pattern = Pattern.compile("[, |]+"); 
String[] strs = pattern.split("Java Hello World Java,Hello,,World|Sun"); 
for (int i=0;i<strs.length;i++) { 
 System.out.println(strs[i]); 
}

文字替换(首次出现字符)

Pattern pattern = Pattern.compile("正则表达式"); 
Matcher matcher = pattern.matcher("正则表达式 Hello World,正则表达式 Hello World"); 
//替换第一个符合正则的数据 
System.out.println(matcher.replaceFirst("Java"));

文字替换(全部)

Pattern pattern = Pattern.compile("正则表达式"); 
Matcher matcher = pattern.matcher("正则表达式 Hello World,正则表达式 Hello World"); 
//替换第一个符合正则的数据 
System.out.println(matcher.replaceAll("Java"));

文字替换(置换字符)

Pattern pattern = Pattern.compile("正则表达式"); 
Matcher matcher = pattern.matcher("正则表达式 Hello World,正则表达式 Hello World "); 
StringBuffer sbr = new StringBuffer(); 
while (matcher.find()) { 
 matcher.appendReplacement(sbr, "Java"); 
} 
matcher.appendTail(sbr); 
System.out.println(sbr.toString());

验证是否为邮箱地址

String str="ceponline@yahoo.com.cn"; 
Pattern pattern = Pattern.compile("[//w//.//-]+@([//w//-]+//.)+[//w//-]+",Pattern.CASE_INSENSITIVE); 
Matcher matcher = pattern.matcher(str); 
System.out.println(matcher.matches());

去除html标记

Pattern pattern = Pattern.compile("<.+?>", Pattern.DOTALL); 
Matcher matcher = pattern.matcher("<a href=/"index.html/">主页</a>"); 
String string = matcher.replaceAll(""); 
System.out.println(string);

查找html中对应条件字符串

Pattern pattern = Pattern.compile("href=/"(.+?)/""); 
Matcher matcher = pattern.matcher("<a href=/"index.html/">主页</a>"); 
if(matcher.find()) 
 System.out.println(matcher.group(1)); 
}

截取http://地址

Pattern pattern = Pattern.compile("(http://|https://){1}[//w//.//-/:]+"); 
Matcher matcher = pattern.matcher("dsdsds<http://dsds//gfgffdfd>fdf"); 
StringBuffer buffer = new StringBuffer(); 
while(matcher.find()){ 
 buffer.append(matcher.group()); 
 buffer.append("/r/n"); 
System.out.println(buffer.toString()); 
}

替换指定{}中文字

String str = "Java目前的发展史是由{0}年-{1}年"; 
String[][] object={new String[]{"//{0//}","1995"},new String[]{"//{1//}","2007"}}; 
System.out.println(replace(str,object)); 
 
public static String replace(final String sourceString,Object[] object) { 
 String temp=sourceString; 
 for(int i=0;i<object.length;i++){ 
 String[] result=(String[])object[i]; 
 Pattern pattern = Pattern.compile(result[0]); 
 Matcher matcher = pattern.matcher(temp); 
 temp=matcher.replaceAll(result[1]); 
 } 
 return temp; 
}

最后附上我自己的两个案例:

匹配类似+59.00-59.0,就是完成一个浮点数的加减表达式

 ((\\-|\\+)?\\d+(\\.\\d+)?)*

匹配HTML的图片标签

/[a-z]{2}-[a-z]{7}/[A-Za-z|-|/|.|0-9]+(.jpg|.png|.gif|.zip|.gz|.7z|.rar|.txt|.bz2


0条评论

发表评论